http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/notebook/Zeppelin Tutorial/Using Pig for querying data_2C57UKYWR.zpln ---------------------------------------------------------------------- diff --git a/notebook/Zeppelin Tutorial/Using Pig for querying data_2C57UKYWR.zpln b/notebook/Zeppelin Tutorial/Using Pig for querying data_2C57UKYWR.zpln new file mode 100644 index 0000000..04cb008 --- /dev/null +++ b/notebook/Zeppelin Tutorial/Using Pig for querying data_2C57UKYWR.zpln @@ -0,0 +1,334 @@ +{ + "paragraphs": [ + { + "text": "%md\n\n\n### [Apache Pig](http://pig.apache.org/) is a platform for analyzing large data sets that consists of a high-level language for expressing data analysis programs, coupled with infrastructure for evaluating these programs. The salient property of Pig programs is that their structure is amenable to substantial parallelization, which in turns enables them to handle very large data sets.\n\nPig\u0027s language layer currently consists of a textual language called Pig Latin, which has the following key properties:\n\n* Ease of programming. It is trivial to achieve parallel execution of simple, \"embarrassingly parallel\" data analysis tasks. Complex tasks comprised of multiple interrelated data transformations are explicitly encoded as data flow sequences, making them easy to write, understand, and maintain.\n* Optimization opportunities. The way in which tasks are encoded permits the system to optimize their execution automatically, allowing the user to focus on semantics rather than efficiency.\n* Extensibility. Users can create their own functions to do special-purpose processing.\n", + "user": "anonymous", + "dateUpdated": "Jan 22, 2017 12:48:50 PM", + "config": { + "colWidth": 12.0, + "enabled": true, + "results": {}, + "editorSetting": { + "language": "markdown", + "editOnDblClick": true + }, + "editorMode": "ace/mode/markdown", + "editorHide": true, + "tableHide": false + }, + "settings": { + "params": {}, + "forms": {} + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "HTML", + "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003ch3\u003e\u003ca href\u003d\"http://pig.apache.org/\"\u003eApache Pig\u003c/a\u003e is a platform for analyzing large data sets that consists of a high-level language for expressing data analysis programs, coupled with infrastructure for evaluating these programs. The salient property of Pig programs is that their structure is amenable to substantial parallelization, which in turns enables them to handle very large data sets.\u003c/h3\u003e\n\u003cp\u003ePig\u0026rsquo;s language layer currently consists of a textual language called Pig Latin, which has the following key properties:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003eEase of programming. It is trivial to achieve parallel execution of simple, \u0026ldquo;embarrassingly parallel\u0026rdquo; data analysis tasks. Complex tasks comprised of multiple interrelated data transformations are explicitly encoded as data flow sequences, making them easy to write, understand, and maintain.\u003c/li\u003e\n \u003cli\u003eOptimization opportunities. The way in which tasks are encoded permits the system to optimize their execution automatically, allowing the user to focus on semantics rather than efficiency.\u003c/li\u003e\n \u003cli\u003eExtensibility. Users can create their own functions to do special-purpose processing.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e" + } + ] + }, + "apps": [], + "jobName": "paragraph_1483277502513_1156234051", + "id": "20170101-213142_1565013608", + "dateCreated": "Jan 1, 2017 9:31:42 PM", + "dateStarted": "Jan 22, 2017 12:48:50 PM", + "dateFinished": "Jan 22, 2017 12:48:51 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%md\n\nThis pig tutorial use pig to do the same thing as spark tutorial. The default mode is mapreduce, you can also use other modes like local/tez_local/tez. For mapreduce mode, you need to have hadoop installed and export `HADOOP_CONF_DIR` in `zeppelin-env.sh`\n\nThe tutorial consists of 3 steps.\n\n* Use shell interpreter to download bank.csv and upload it to hdfs\n* use `%pig` to process the data\n* use `%pig.query` to query the data", + "user": "anonymous", + "dateUpdated": "Jan 22, 2017 12:48:55 PM", + "config": { + "colWidth": 12.0, + "enabled": true, + "results": {}, + "editorSetting": { + "language": "markdown", + "editOnDblClick": true + }, + "editorMode": "ace/mode/markdown", + "editorHide": true, + "tableHide": false + }, + "settings": { + "params": {}, + "forms": {} + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "HTML", + "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003cp\u003eThis pig tutorial use pig to do the same thing as spark tutorial. The default mode is mapreduce, you can also use other modes like local/tez_local/tez. For mapreduce mode, you need to have hadoop installed and export \u003ccode\u003eHADOOP_CONF_DIR\u003c/code\u003e in \u003ccode\u003ezeppelin-env.sh\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eThe tutorial consists of 3 steps.\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003eUse shell interpreter to download bank.csv and upload it to hdfs\u003c/li\u003e\n \u003cli\u003euse \u003ccode\u003e%pig\u003c/code\u003e to process the data\u003c/li\u003e\n \u003cli\u003euse \u003ccode\u003e%pig.query\u003c/code\u003e to query the data\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e" + } + ] + }, + "apps": [], + "jobName": "paragraph_1483689316217_-629483391", + "id": "20170106-155516_1050601059", + "dateCreated": "Jan 6, 2017 3:55:16 PM", + "dateStarted": "Jan 22, 2017 12:48:55 PM", + "dateFinished": "Jan 22, 2017 12:48:55 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%sh\n\nwget https://s3.amazonaws.com/apache-zeppelin/tutorial/bank/bank.csv\nhadoop fs -put bank.csv .\n", + "user": "anonymous", + "dateUpdated": "Jan 22, 2017 12:51:48 PM", + "config": { + "colWidth": 12.0, + "enabled": true, + "results": {}, + "editorSetting": { + "language": "text", + "editOnDblClick": false + }, + "editorMode": "ace/mode/text" + }, + "settings": { + "params": {}, + "forms": {} + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TEXT", + "data": "--2017-01-22 12:51:48-- https://s3.amazonaws.com/apache-zeppelin/tutorial/bank/bank.csv\nResolving s3.amazonaws.com... 52.216.80.227\nConnecting to s3.amazonaws.com|52.216.80.227|:443... connected.\nHTTP request sent, awaiting response... 200 OK\nLength: 461474 (451K) [application/octet-stream]\nSaving to: \u0027bank.csv.3\u0027\n\n 0K .......... .......... .......... .......... .......... 11% 141K 3s\n 50K .......... .......... .......... .......... .......... 22% 243K 2s\n 100K .......... .......... .......... .......... .......... 33% 449K 1s\n 150K .......... .......... .......... .......... .......... 44% 413K 1s\n 200K .......... .......... .......... .......... .......... 55% 746K 1s\n 250K .......... .......... .......... .......... .......... 66% 588K 0s\n 300K .......... .......... .......... .......... .......... 77% 840K 0s\n 350K .......... .......... .......... .......... .......... 88% 795K 0s\n 400K .......... ...... .... .......... .......... .......... 99% 1.35M 0s\n 450K 100% 13.2K\u003d1.1s\n\n2017-01-22 12:51:50 (409 KB/s) - \u0027bank.csv.3\u0027 saved [461474/461474]\n\n17/01/22 12:51:51 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" + } + ] + }, + "apps": [], + "jobName": "paragraph_1485058437578_-1906301827", + "id": "20170122-121357_640055590", + "dateCreated": "Jan 22, 2017 12:13:57 PM", + "dateStarted": "Jan 22, 2017 12:51:48 PM", + "dateFinished": "Jan 22, 2017 12:51:52 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%pig\n\nbankText \u003d load \u0027bank.csv\u0027 using PigStorage(\u0027;\u0027);\nbank \u003d foreach bankText generate $0 as age, $1 as job, $2 as marital, $3 as education, $5 as balance; \nbank \u003d filter bank by age !\u003d \u0027\"age\"\u0027;\nbank \u003d foreach bank generate (int)age, REPLACE(job,\u0027\"\u0027,\u0027\u0027) as job, REPLACE(marital, \u0027\"\u0027, \u0027\u0027) as marital, (int)(REPLACE(balance, \u0027\"\u0027, \u0027\u0027)) as balance;\n\n-- The following statement is optional, it depends on whether your needs.\n-- store bank into \u0027clean_bank.csv\u0027 using PigStorage(\u0027;\u0027);\n\n\n", + "user": "anonymous", + "dateUpdated": "Feb 24, 2017 5:08:08 PM", + "config": { + "colWidth": 12.0, + "editorMode": "ace/mode/pig", + "results": {}, + "enabled": true, + "editorSetting": { + "language": "pig", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "results": { + "code": "SUCCESS", + "msg": [] + }, + "apps": [], + "jobName": "paragraph_1483277250237_-466604517", + "id": "20161228-140640_1560978333", + "dateCreated": "Jan 1, 2017 9:27:30 PM", + "dateStarted": "Feb 24, 2017 5:08:08 PM", + "dateFinished": "Feb 24, 2017 5:08:11 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%pig.query\n\nbank_data \u003d filter bank by age \u003c 30;\nb \u003d group bank_data by age;\nforeach b generate group, COUNT($1);\n\n", + "user": "anonymous", + "dateUpdated": "Feb 24, 2017 5:08:13 PM", + "config": { + "colWidth": 4.0, + "editorMode": "ace/mode/pig", + "results": { + "0": { + "graph": { + "mode": "multiBarChart", + "height": 300.0, + "optionOpen": false + }, + "helium": {} + } + }, + "enabled": true, + "editorSetting": { + "language": "pig", + "editOnDblClick": false + } + }, + "settings": { + "params": {}, + "forms": {} + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "group\tcol_1\n19\t4\n20\t3\n21\t7\n22\t9\n23\t20\n24\t24\n25\t44\n26\t77\n27\t94\n28\t103\n29\t97\n" + } + ] + }, + "apps": [], + "jobName": "paragraph_1483277250238_-465450270", + "id": "20161228-140730_1903342877", + "dateCreated": "Jan 1, 2017 9:27:30 PM", + "dateStarted": "Feb 24, 2017 5:08:13 PM", + "dateFinished": "Feb 24, 2017 5:08:26 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%pig.query\n\nbank_data \u003d filter bank by age \u003c ${maxAge\u003d40};\nb \u003d group bank_data by age;\nforeach b generate group, COUNT($1) as count;", + "user": "anonymous", + "dateUpdated": "Feb 24, 2017 5:08:14 PM", + "config": { + "colWidth": 4.0, + "editorMode": "ace/mode/pig", + "results": { + "0": { + "graph": { + "mode": "pieChart", + "height": 300.0, + "optionOpen": false + }, + "helium": {} + } + }, + "enabled": true, + "editorSetting": { + "language": "pig", + "editOnDblClick": false + } + }, + "settings": { + "params": { + "maxAge": "36" + }, + "forms": { + "maxAge": { + "name": "maxAge", + "defaultValue": "40", + "hidden": false + } + } + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "group\tcount\n19\t4\n20\t3\n21\t7\n22\t9\n23\t20\n24\t24\n25\t44\n26\t77\n27\t94\n28\t103\n29\t97\n30\t150\n31\t199\n32\t224\n33\t186\n34\t231\n35\t180\n" + } + ] + }, + "apps": [], + "jobName": "paragraph_1483277250239_-465835019", + "id": "20161228-154918_1551591203", + "dateCreated": "Jan 1, 2017 9:27:30 PM", + "dateStarted": "Feb 24, 2017 5:08:14 PM", + "dateFinished": "Feb 24, 2017 5:08:29 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%pig.query\n\nbank_data \u003d filter bank by marital\u003d\u003d\u0027${marital\u003dsingle,single|divorced|married}\u0027;\nb \u003d group bank_data by age;\nforeach b generate group, COUNT($1) as count;\n\n\n", + "user": "anonymous", + "dateUpdated": "Feb 24, 2017 5:08:15 PM", + "config": { + "colWidth": 4.0, + "editorMode": "ace/mode/pig", + "results": { + "0": { + "graph": { + "mode": "scatterChart", + "height": 300.0, + "optionOpen": false + }, + "helium": {} + } + }, + "enabled": true, + "editorSetting": { + "language": "pig", + "editOnDblClick": false + } + }, + "settings": { + "params": { + "marital": "married" + }, + "forms": { + "marital": { + "name": "marital", + "defaultValue": "single", + "options": [ + { + "value": "single" + }, + { + "value": "divorced" + }, + { + "value": "married" + } + ], + "hidden": false + } + } + }, + "results": { + "code": "SUCCESS", + "msg": [ + { + "type": "TABLE", + "data": "group\tcount\n23\t3\n24\t11\n25\t11\n26\t18\n27\t26\n28\t23\n29\t37\n30\t56\n31\t104\n32\t105\n33\t103\n34\t142\n35\t109\n36\t117\n37\t100\n38\t99\n39\t88\n40\t105\n41\t97\n42\t91\n43\t79\n44\t68\n45\t76\n46\t82\n47\t78\n48\t91\n49\t87\n50\t74\n51\t63\n52\t66\n53\t75\n54\t56\n55\t68\n56\t50\n57\t78\n58\t67\n59\t56\n60\t36\n61\t15\n62\t5\n63\t7\n64\t6\n65\t4\n66\t7\n67\t5\n68\t1\n69\t5\n70\t5\n71\t5\n72\t4\n73\t6\n74\t2\n75\t3\n76\t1\n77\t5\n78\t2\n79\t3\n80\t6\n81\t1\n83\t2\n86\t1\n87\t1\n" + } + ] + }, + "apps": [], + "jobName": "paragraph_1483277250240_-480070728", + "id": "20161228-142259_575675591", + "dateCreated": "Jan 1, 2017 9:27:30 PM", + "dateStarted": "Feb 24, 2017 5:08:27 PM", + "dateFinished": "Feb 24, 2017 5:08:31 PM", + "status": "FINISHED", + "progressUpdateIntervalMs": 500 + }, + { + "text": "%pig\n", + "dateUpdated": "Jan 1, 2017 9:27:30 PM", + "config": {}, + "settings": { + "params": {}, + "forms": {} + }, + "apps": [], + "jobName": "paragraph_1483277250240_-480070728", + "id": "20161228-155036_1854903164", + "dateCreated": "Jan 1, 2017 9:27:30 PM", + "status": "READY", + "errorMessage": "", + "progressUpdateIntervalMs": 500 + } + ], + "name": "Using Pig for querying data", + "id": "2C57UKYWR", + "angularObjects": { + "2C3RWCVAG:shared_process": [], + "2C9KGCHDE:shared_process": [], + "2C8X2BS16:shared_process": [] + }, + "config": {}, + "info": {} +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/SchedulerFactory.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/SchedulerFactory.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/SchedulerFactory.java index a4d16ee..ab8cd66 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/SchedulerFactory.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/SchedulerFactory.java @@ -110,5 +110,5 @@ public class SchedulerFactory { public ExecutorService getExecutor() { return executor; } - + } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java index 12dbd90..e1e10e6 100644 --- a/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java +++ b/zeppelin-plugins/notebookrepo/azure/src/main/java/org/apache/zeppelin/notebook/repo/AzureNotebookRepo.java @@ -24,15 +24,12 @@ import com.microsoft.azure.storage.file.CloudFileClient; import com.microsoft.azure.storage.file.CloudFileDirectory; import com.microsoft.azure.storage.file.CloudFileShare; import com.microsoft.azure.storage.file.ListFileItem; -import java.io.ByteArrayOutputStream; + import java.io.IOException; import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; import java.net.URISyntaxException; -import java.security.InvalidKeyException; import java.util.Collections; -import java.util.LinkedList; +import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; @@ -48,7 +45,7 @@ import org.slf4j.LoggerFactory; * Azure storage backend for notebooks */ public class AzureNotebookRepo implements NotebookRepo { - private static final Logger LOG = LoggerFactory.getLogger(AzureNotebookRepo.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AzureNotebookRepo.class); private ZeppelinConfiguration conf; private String user; @@ -84,50 +81,46 @@ public class AzureNotebookRepo implements NotebookRepo { } @Override - public List<NoteInfo> list(AuthenticationInfo subject) throws IOException { - List<NoteInfo> infos = new LinkedList<>(); - NoteInfo info = null; + public Map<String, NoteInfo> list(AuthenticationInfo subject) throws IOException { + return list(rootDir); + } + private Map<String, NoteInfo> list(CloudFileDirectory folder) throws IOException { + Map<String, NoteInfo> notesInfo = new HashMap<>(); for (ListFileItem item : rootDir.listFilesAndDirectories()) { - if (item.getClass() == CloudFileDirectory.class) { + if (item instanceof CloudFileDirectory) { CloudFileDirectory dir = (CloudFileDirectory) item; - - try { - if (dir.getFileReference("note.json").exists()) { - info = new NoteInfo(getNote(dir.getName())); - - if (info != null) { - infos.add(info); - } + notesInfo.putAll(list(dir)); + } else if (item instanceof CloudFile){ + CloudFile file = (CloudFile) item; + if (file.getName().endsWith(".zpln")) { + try { + String noteName = getNotePath(rootDir.getUri().getPath(), file.getUri().getPath()); + String noteId = getNoteId(file.getUri().getPath()); + notesInfo.put(noteId, new NoteInfo(noteId, noteName)); + } catch (IOException e) { + LOGGER.warn(e.getMessage()); } - } catch (StorageException | URISyntaxException e) { - String msg = "Error enumerating notebooks from Azure storage"; - LOG.error(msg, e); - } catch (Exception e) { - LOG.error(e.getMessage(), e); + } else { + LOGGER.debug("Skip invalid note file: " + file.getUri().getPath()); } } } - - return infos; + return notesInfo; } - private Note getNote(String noteId) throws IOException { + @Override + public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException { InputStream ins = null; - try { - CloudFileDirectory dir = rootDir.getDirectoryReference(noteId); - CloudFile file = dir.getFileReference("note.json"); - - ins = file.openRead(); + CloudFile noteFile = rootDir.getFileReference(buildNoteFileName(noteId, notePath)); + ins = noteFile.openRead(); } catch (URISyntaxException | StorageException e) { - String msg = String.format("Error reading notebook %s from Azure storage", noteId); - - LOG.error(msg, e); - + String msg = String.format("Error reading notebook %s from Azure storage", + buildNoteFileName(noteId, notePath)); + LOGGER.error(msg, e); throw new IOException(msg, e); } - String json = IOUtils.toString(ins, conf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_ENCODING)); ins.close(); @@ -135,82 +128,60 @@ public class AzureNotebookRepo implements NotebookRepo { } @Override - public Note get(String noteId, AuthenticationInfo subject) throws IOException { - return getNote(noteId); - } - - @Override public void save(Note note, AuthenticationInfo subject) throws IOException { - String json = note.toJson(); - - ByteArrayOutputStream output = new ByteArrayOutputStream(); - Writer writer = new OutputStreamWriter(output); - writer.write(json); - writer.close(); - output.close(); - - byte[] buffer = output.toByteArray(); - try { - CloudFileDirectory dir = rootDir.getDirectoryReference(note.getId()); - dir.createIfNotExists(); - - CloudFile cloudFile = dir.getFileReference("note.json"); - cloudFile.uploadFromByteArray(buffer, 0, buffer.length); + CloudFile noteFile = rootDir.getFileReference(buildNoteFileName(note)); + noteFile.getParent().createIfNotExists(); + noteFile.uploadText(note.toJson()); } catch (URISyntaxException | StorageException e) { - String msg = String.format("Error saving notebook %s to Azure storage", note.getId()); - - LOG.error(msg, e); - + String msg = String.format("Error saving notebook %s to Azure storage", + buildNoteFileName(note)); + LOGGER.error(msg, e); throw new IOException(msg, e); } } - // unfortunately, we need to use a recursive delete here - private void delete(ListFileItem item) throws StorageException { - if (item.getClass() == CloudFileDirectory.class) { - CloudFileDirectory dir = (CloudFileDirectory) item; + @Override + public void move(String noteId, String notePath, String newNotePath, AuthenticationInfo subject) { - for (ListFileItem subItem : dir.listFilesAndDirectories()) { - delete(subItem); - } + } - dir.deleteIfExists(); - } else if (item.getClass() == CloudFile.class) { - CloudFile file = (CloudFile) item; + @Override + public void move(String folderPath, String newFolderPath, AuthenticationInfo subject) { - file.deleteIfExists(); - } } @Override - public void remove(String noteId, AuthenticationInfo subject) throws IOException { + public void remove(String noteId, String notePath, AuthenticationInfo subject) throws IOException { try { - CloudFileDirectory dir = rootDir.getDirectoryReference(noteId); - - delete(dir); + CloudFile noteFile = rootDir.getFileReference(buildNoteFileName(noteId, notePath)); + noteFile.delete(); } catch (URISyntaxException | StorageException e) { - String msg = String.format("Error deleting notebook %s from Azure storage", noteId); - - LOG.error(msg, e); - + String msg = String.format("Error deleting notebook %s from Azure storage", + buildNoteFileName(noteId, notePath)); + LOGGER.error(msg, e); throw new IOException(msg, e); } } @Override + public void remove(String folderPath, AuthenticationInfo subject) { + + } + + @Override public void close() { } @Override public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo subject) { - LOG.warn("Method not implemented"); + LOGGER.warn("Method not implemented"); return Collections.emptyList(); } @Override public void updateSettings(Map<String, String> settings, AuthenticationInfo subject) { - LOG.warn("Method not implemented"); + LOGGER.warn("Method not implemented"); } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java index 5d9c85c..e7b03ca 100644 --- a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java +++ b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java @@ -1,12 +1,23 @@ +/* + * 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.notebook.repo; -import org.apache.commons.lang.StringUtils; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.io.IOUtils; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.notebook.FileSystemStorage; import org.apache.zeppelin.notebook.Note; @@ -15,25 +26,14 @@ import org.apache.zeppelin.user.AuthenticationInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; /** * NotebookRepos for hdfs. * - * Assume the notebook directory structure is as following - * - notebookdir - * - noteId/note.json - * - noteId/note.json - * - noteId/note.json */ public class FileSystemNotebookRepo implements NotebookRepo { private static final Logger LOGGER = LoggerFactory.getLogger(FileSystemNotebookRepo.class); @@ -47,41 +47,73 @@ public class FileSystemNotebookRepo implements NotebookRepo { public void init(ZeppelinConfiguration zConf) throws IOException { this.fs = new FileSystemStorage(zConf, zConf.getNotebookDir()); - LOGGER.info("Creating FileSystem: " + this.fs.getFs().getClass().getName() + - " for Zeppelin Notebook."); + LOGGER.info("Creating FileSystem: " + this.fs.getFs().getClass().getName()); this.notebookDir = this.fs.makeQualified(new Path(zConf.getNotebookDir())); LOGGER.info("Using folder {} to store notebook", notebookDir); this.fs.tryMkDir(notebookDir); } @Override - public List<NoteInfo> list(AuthenticationInfo subject) throws IOException { - List<Path> notePaths = fs.list(new Path(notebookDir, "*/note.json")); - List<NoteInfo> noteInfos = new ArrayList<>(); + public Map<String, NoteInfo> list(AuthenticationInfo subject) throws IOException { + List<Path> notePaths = fs.listAll(notebookDir); + Map<String, NoteInfo> noteInfos = new HashMap<>(); for (Path path : notePaths) { - NoteInfo noteInfo = new NoteInfo(path.getParent().getName(), "", null); - noteInfos.add(noteInfo); + try { + NoteInfo noteInfo = new NoteInfo(getNoteId(path.getName()), + getNotePath(notebookDir.toString(), path.toString())); + noteInfos.put(noteInfo.getId(), noteInfo); + } catch (IOException e) { + LOGGER.warn("Fail to get NoteInfo for note: " + path.getName(), e); + } } return noteInfos; } + @Override - public Note get(final String noteId, AuthenticationInfo subject) throws IOException { + public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException { String content = this.fs.readFile( - new Path(notebookDir.toString() + "/" + noteId + "/note.json")); + new Path(notebookDir, buildNoteFileName(noteId, notePath))); return Note.fromJson(content); } @Override - public void save(final Note note, AuthenticationInfo subject) throws IOException { + public void save(Note note, AuthenticationInfo subject) throws IOException { this.fs.writeFile(note.toJson(), - new Path(notebookDir.toString() + "/" + note.getId() + "/note.json"), + new Path(notebookDir, buildNoteFileName(note.getId(), note.getPath())), true); } @Override - public void remove(final String noteId, AuthenticationInfo subject) throws IOException { - this.fs.delete(new Path(notebookDir.toString() + "/" + noteId)); + public void move(String noteId, + String notePath, + String newNotePath, + AuthenticationInfo subject) throws IOException { + Path src = new Path(notebookDir, buildNoteFileName(noteId, notePath)); + Path dest = new Path(notebookDir, buildNoteFileName(noteId, newNotePath)); + this.fs.move(src, dest); + } + + @Override + public void move(String folderPath, String newFolderPath, AuthenticationInfo subject) + throws IOException { + this.fs.move(new Path(notebookDir, folderPath.substring(1)), + new Path(notebookDir, newFolderPath.substring(1))); + } + + @Override + public void remove(String noteId, String notePath, AuthenticationInfo subject) + throws IOException { + if (!this.fs.delete(new Path(notebookDir.toString(), buildNoteFileName(noteId, notePath)))) { + LOGGER.warn("Fail to move note, noteId: " + notePath + ", notePath: " + notePath); + } + } + + @Override + public void remove(String folderPath, AuthenticationInfo subject) throws IOException { + if (!this.fs.delete(new Path(notebookDir, folderPath.substring(1)))) { + LOGGER.warn("Fail to remove folder: " + folderPath); + } } @Override http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/filesystem/src/test/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepoTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/filesystem/src/test/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepoTest.java b/zeppelin-plugins/notebookrepo/filesystem/src/test/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepoTest.java index 5fd8becc..3301daa 100644 --- a/zeppelin-plugins/notebookrepo/filesystem/src/test/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepoTest.java +++ b/zeppelin-plugins/notebookrepo/filesystem/src/test/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepoTest.java @@ -1,3 +1,20 @@ +/* + * 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.notebook.repo; @@ -7,6 +24,7 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.notebook.NoteInfo; import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.After; import org.junit.Before; @@ -52,7 +70,7 @@ public class FileSystemNotebookRepoTest { // create a new note Note note = new Note(); - note.setName("title_1"); + note.setPath("/title_1"); Map<String, Object> config = new HashMap<>(); config.put("config_1", "value_1"); @@ -61,20 +79,43 @@ public class FileSystemNotebookRepoTest { assertEquals(1, hdfsNotebookRepo.list(authInfo).size()); // read this note from hdfs - Note note_copy = hdfsNotebookRepo.get(note.getId(), authInfo); + Note note_copy = hdfsNotebookRepo.get(note.getId(), note.getPath(), authInfo); assertEquals(note.getName(), note_copy.getName()); assertEquals(note.getConfig(), note_copy.getConfig()); // update this note - note.setName("title_2"); + note.setPersonalizedMode(true); hdfsNotebookRepo.save(note, authInfo); assertEquals(1, hdfsNotebookRepo.list(authInfo).size()); - note_copy = hdfsNotebookRepo.get(note.getId(), authInfo); + note_copy = hdfsNotebookRepo.get(note.getId(), note.getPath(), authInfo); assertEquals(note.getName(), note_copy.getName()); assertEquals(note.getConfig(), note_copy.getConfig()); + // move this note + String newPath = "/new_folder/title_1"; + hdfsNotebookRepo.move(note.getId(), note.getPath(), newPath, authInfo); + assertEquals(1, hdfsNotebookRepo.list(authInfo).size()); + assertEquals("title_1", hdfsNotebookRepo.get(note.getId(), newPath, authInfo).getName()); + // delete this note - hdfsNotebookRepo.remove(note.getId(), authInfo); + hdfsNotebookRepo.remove(note.getId(), newPath, authInfo); + assertEquals(0, hdfsNotebookRepo.list(authInfo).size()); + + // create another new note under folder + note = new Note(); + note.setPath("/folder1/title_1"); + note.setConfig(config); + hdfsNotebookRepo.save(note, authInfo); + assertEquals(1, hdfsNotebookRepo.list(authInfo).size()); + + hdfsNotebookRepo.move("/folder1", "/folder2/folder3", authInfo); + Map<String, NoteInfo> notesInfo = hdfsNotebookRepo.list(authInfo); + assertEquals(1, notesInfo.size()); + + assertEquals("/folder2/folder3/title_1", notesInfo.get(note.getId()).getPath()); + + // delete folder + hdfsNotebookRepo.remove("/folder2", authInfo); assertEquals(0, hdfsNotebookRepo.list(authInfo).size()); } @@ -90,12 +131,11 @@ public class FileSystemNotebookRepoTest { // scenario_2: note_folder is existed. // create a new note Note note = new Note(); - note.setName("title_1"); + note.setPath("/title_1"); Map<String, Object> config = new HashMap<>(); config.put("config_1", "value_1"); note.setConfig(config); - fs.mkdirs(new Path(notebookDir, note.getId())); hdfsNotebookRepo.save(note, authInfo); assertEquals(1, hdfsNotebookRepo.list(authInfo).size()); } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/filesystem/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/filesystem/src/test/resources/log4j.properties b/zeppelin-plugins/notebookrepo/filesystem/src/test/resources/log4j.properties new file mode 100644 index 0000000..8daee59 --- /dev/null +++ b/zeppelin-plugins/notebookrepo/filesystem/src/test/resources/log4j.properties @@ -0,0 +1,22 @@ +# +# 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. +# + +log4j.rootLogger = INFO, stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%d] ({%t} %F[%M]:%L) - %m%n http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java index ad99aba..ee269df 100644 --- a/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java +++ b/zeppelin-plugins/notebookrepo/gcs/src/main/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepo.java @@ -30,9 +30,9 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.gson.JsonParseException; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -60,11 +60,11 @@ import org.slf4j.LoggerFactory; */ public class GCSNotebookRepo implements NotebookRepo { - private static final Logger LOG = LoggerFactory.getLogger(GCSNotebookRepo.class); + private static final Logger LOGGER = LoggerFactory.getLogger(GCSNotebookRepo.class); private String encoding; private String bucketName; private Optional<String> basePath; - private Pattern noteNamePattern; + private Pattern notePathPattern; private Storage storage; public GCSNotebookRepo() { @@ -107,27 +107,27 @@ public class GCSNotebookRepo implements NotebookRepo { // Notes are stored at gs://bucketName/basePath/<note-id>/note.json if (basePath.isPresent()) { - this.noteNamePattern = Pattern.compile( - "^" + Pattern.quote(basePath.get() + "/") + "([^/]+)/note\\.json$"); + this.notePathPattern = Pattern.compile( + "^" + Pattern.quote(basePath.get() + "/") + "(.+\\.zpln)$"); } else { - this.noteNamePattern = Pattern.compile("^([^/]+)/note\\.json$"); + this.notePathPattern = Pattern.compile("^(.+\\.zpln)$"); } this.storage = StorageOptions.getDefaultInstance().getService(); } - private BlobId makeBlobId(String noteId) { + private BlobId makeBlobId(String noteId, String notePath) throws IOException { if (basePath.isPresent()) { - return BlobId.of(bucketName, basePath.get() + "/" + noteId + "/note.json"); + return BlobId.of(bucketName, basePath.get() + "/" + buildNoteFileName(noteId, notePath)); } else { - return BlobId.of(bucketName, noteId + "/note.json"); + return BlobId.of(bucketName, buildNoteFileName(noteId, notePath)); } } @Override - public List<NoteInfo> list(AuthenticationInfo subject) throws IOException { + public Map<String, NoteInfo> list(AuthenticationInfo subject) throws IOException { try { - List<NoteInfo> infos = new ArrayList<>(); + Map<String, NoteInfo> infos = new HashMap<>(); Iterable<Blob> blobsUnderDir; if (basePath.isPresent()) { blobsUnderDir = storage @@ -139,11 +139,18 @@ public class GCSNotebookRepo implements NotebookRepo { .iterateAll(); } for (Blob b : blobsUnderDir) { - Matcher matcher = noteNamePattern.matcher(b.getName()); + Matcher matcher = notePathPattern.matcher(b.getName()); if (matcher.matches()) { // Callers only use the id field, so do not fetch each note // This matches the implementation in FileSystemNoteRepo#list - infos.add(new NoteInfo(matcher.group(1), "", null)); + String noteFileName = matcher.group(1); + try { + String noteId = getNoteId(noteFileName); + String notePath = getNotePath("", noteFileName); + infos.put(noteId, new NoteInfo(noteId, notePath)); + } catch (IOException e) { + LOGGER.warn(e.getMessage()); + } } } return infos; @@ -153,8 +160,8 @@ public class GCSNotebookRepo implements NotebookRepo { } @Override - public Note get(String noteId, AuthenticationInfo subject) throws IOException { - BlobId blobId = makeBlobId(noteId); + public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException { + BlobId blobId = makeBlobId(noteId, notePath); byte[] contents; try { contents = storage.readAllBytes(blobId); @@ -172,7 +179,7 @@ public class GCSNotebookRepo implements NotebookRepo { @Override public void save(Note note, AuthenticationInfo subject) throws IOException { - BlobInfo info = BlobInfo.newBuilder(makeBlobId(note.getId())) + BlobInfo info = BlobInfo.newBuilder(makeBlobId(note.getId(), note.getPath())) .setContentType("application/json") .build(); try { @@ -183,9 +190,19 @@ public class GCSNotebookRepo implements NotebookRepo { } @Override - public void remove(String noteId, AuthenticationInfo subject) throws IOException { + public void move(String noteId, String notePath, String newNotePath, AuthenticationInfo subject) { + + } + + @Override + public void move(String folderPath, String newFolderPath, AuthenticationInfo subject) { + + } + + @Override + public void remove(String noteId, String notePath, AuthenticationInfo subject) throws IOException { Preconditions.checkArgument(!Strings.isNullOrEmpty(noteId)); - BlobId blobId = makeBlobId(noteId); + BlobId blobId = makeBlobId(noteId, notePath); try { boolean deleted = storage.delete(blobId); if (!deleted) { @@ -197,18 +214,23 @@ public class GCSNotebookRepo implements NotebookRepo { } @Override + public void remove(String folderPath, AuthenticationInfo subject) { + + } + + @Override public void close() { //no-op } @Override public List<NotebookRepoSettingsInfo> getSettings(AuthenticationInfo subject) { - LOG.warn("getSettings is not implemented for GCSNotebookRepo"); + LOGGER.warn("getSettings is not implemented for GCSNotebookRepo"); return Collections.emptyList(); } @Override public void updateSettings(Map<String, String> settings, AuthenticationInfo subject) { - LOG.warn("updateSettings is not implemented for GCSNotebookRepo"); + LOGGER.warn("updateSettings is not implemented for GCSNotebookRepo"); } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/gcs/src/test/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepoTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/gcs/src/test/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepoTest.java b/zeppelin-plugins/notebookrepo/gcs/src/test/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepoTest.java index c1fae67..f2e19d0 100644 --- a/zeppelin-plugins/notebookrepo/gcs/src/test/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepoTest.java +++ b/zeppelin-plugins/notebookrepo/gcs/src/test/java/org/apache/zeppelin/notebook/repo/GCSNotebookRepoTest.java @@ -32,6 +32,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; + import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.notebook.Note; @@ -86,9 +88,10 @@ public class GCSNotebookRepoTest { private static Note makeRunningNote() { Note note = new Note(); + note.setPath("/test_note"); note.setConfig(ImmutableMap.<String, Object>of("key", "value")); - Paragraph p = new Paragraph(note, null, null); + Paragraph p = new Paragraph(note, null); p.setText("text"); p.setStatus(Status.RUNNING); note.addParagraph(p); @@ -102,26 +105,26 @@ public class GCSNotebookRepoTest { @Test public void testList() throws Exception { - createAt(runningNote, "note.json"); - createAt(runningNote, "/note.json"); - createAt(runningNote, "validid/note.json"); - createAt(runningNote, "validid-2/note.json"); + createAt(runningNote, "note.zpln"); + createAt(runningNote, "/note.zpln"); + createAt(runningNote, "validid/my_12.zpln"); + createAt(runningNote, "validid-2/my_123.zpln"); createAt(runningNote, "cannot-be-dir/note.json/foo"); createAt(runningNote, "cannot/be/nested/note.json"); - List<NoteInfo> infos = notebookRepo.list(AUTH_INFO); + Map<String, NoteInfo> infos = notebookRepo.list(AUTH_INFO); List<String> noteIds = new ArrayList<>(); - for (NoteInfo info : infos) { + for (NoteInfo info : infos.values()) { noteIds.add(info.getId()); } // Only valid paths are gs://bucketname/path/<noteid>/note.json - assertThat(noteIds).containsExactlyElementsIn(ImmutableList.of("validid", "validid-2")); + assertThat(noteIds).containsExactlyElementsIn(ImmutableList.of("12", "123")); } @Test public void testGet_nonexistent() throws Exception { try { - notebookRepo.get("id", AUTH_INFO); + notebookRepo.get("id", "", AUTH_INFO); fail(); } catch (IOException e) {} } @@ -131,7 +134,7 @@ public class GCSNotebookRepoTest { create(runningNote); // Status of saved running note is removed in get() - Note got = notebookRepo.get(runningNote.getId(), AUTH_INFO); + Note got = notebookRepo.get(runningNote.getId(), runningNote.getPath(), AUTH_INFO); assertThat(got.getLastParagraph().getStatus()).isEqualTo(Status.ABORT); // But otherwise equal @@ -141,9 +144,9 @@ public class GCSNotebookRepoTest { @Test public void testGet_malformed() throws Exception { - createMalformed("id"); + createMalformed("id", "/name"); try { - notebookRepo.get("id", AUTH_INFO); + notebookRepo.get("id", "/name", AUTH_INFO); fail(); } catch (IOException e) {} } @@ -152,7 +155,7 @@ public class GCSNotebookRepoTest { public void testSave_create() throws Exception { notebookRepo.save(runningNote, AUTH_INFO); // Output is saved - assertThat(storage.readAllBytes(makeBlobId(runningNote.getId()))) + assertThat(storage.readAllBytes(makeBlobId(runningNote.getId(), runningNote.getPath()))) .isEqualTo(runningNote.toJson().getBytes("UTF-8")); } @@ -160,16 +163,16 @@ public class GCSNotebookRepoTest { public void testSave_update() throws Exception { notebookRepo.save(runningNote, AUTH_INFO); // Change name of runningNote - runningNote.setName("new-name"); + runningNote.setPath("/new-name"); notebookRepo.save(runningNote, AUTH_INFO); - assertThat(storage.readAllBytes(makeBlobId(runningNote.getId()))) + assertThat(storage.readAllBytes(makeBlobId(runningNote.getId(), runningNote.getPath()))) .isEqualTo(runningNote.toJson().getBytes("UTF-8")); } @Test public void testRemove_nonexistent() throws Exception { try { - notebookRepo.remove("id", AUTH_INFO); + notebookRepo.remove("id", "/name", AUTH_INFO); fail(); } catch (IOException e) {} } @@ -177,8 +180,8 @@ public class GCSNotebookRepoTest { @Test public void testRemove() throws Exception { create(runningNote); - notebookRepo.remove(runningNote.getId(), AUTH_INFO); - assertThat(storage.get(makeBlobId(runningNote.getId()))).isNull(); + notebookRepo.remove(runningNote.getId(), runningNote.getPath(), AUTH_INFO); + assertThat(storage.get(makeBlobId(runningNote.getId(), runningNote.getPath()))).isNull(); } private String makeName(String relativePath) { @@ -189,8 +192,12 @@ public class GCSNotebookRepoTest { } } - private BlobId makeBlobId(String noteId) { - return BlobId.of(bucketName, makeName(noteId + "/note.json")); + private BlobId makeBlobId(String noteId, String notePath) { + if (basePath.isPresent()) { + return BlobId.of(bucketName, basePath.get() + notePath + "_" + noteId +".zpln"); + } else { + return BlobId.of(bucketName, notePath.substring(1) + "_" + noteId +".zpln"); + } } private void createAt(Note note, String relativePath) throws IOException { @@ -200,14 +207,14 @@ public class GCSNotebookRepoTest { } private void create(Note note) throws IOException { - BlobInfo info = BlobInfo.newBuilder(makeBlobId(note.getId())) + BlobInfo info = BlobInfo.newBuilder(makeBlobId(note.getId(), note.getPath())) .setContentType("application/json") .build(); storage.create(info, note.toJson().getBytes("UTF-8")); } - private void createMalformed(String noteId) throws IOException { - BlobInfo info = BlobInfo.newBuilder(makeBlobId(noteId)) + private void createMalformed(String noteId, String notePath) throws IOException { + BlobInfo info = BlobInfo.newBuilder(makeBlobId(noteId, notePath)) .setContentType("application/json") .build(); storage.create(info, "{ invalid-json }".getBytes("UTF-8")); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/git/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/git/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java b/zeppelin-plugins/notebookrepo/git/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java index 7729d52..2da91fc 100644 --- a/zeppelin-plugins/notebookrepo/git/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java +++ b/zeppelin-plugins/notebookrepo/git/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java @@ -53,9 +53,8 @@ import java.util.List; * TODO(bzz): add default .gitignore */ public class GitNotebookRepo extends VFSNotebookRepo implements NotebookRepoWithVersionControl { - private static final Logger LOG = LoggerFactory.getLogger(GitNotebookRepo.class); + private static final Logger LOGGER = LoggerFactory.getLogger(GitNotebookRepo.class); - private String localPath; private Git git; public GitNotebookRepo() { @@ -75,43 +74,74 @@ public class GitNotebookRepo extends VFSNotebookRepo implements NotebookRepoWith this.conf = conf; setNotebookDirectory(conf.getNotebookDir()); - localPath = getRootDir().getName().getPath(); - LOG.info("Opening a git repo at '{}'", localPath); - Repository localRepo = new FileRepository(Joiner.on(File.separator).join(localPath, ".git")); + LOGGER.info("Opening a git repo at '{}'", this.rootNotebookFolder); + Repository localRepo = new FileRepository(Joiner.on(File.separator) + .join(this.rootNotebookFolder, ".git")); if (!localRepo.getDirectory().exists()) { - LOG.info("Git repo {} does not exist, creating a new one", localRepo.getDirectory()); + LOGGER.info("Git repo {} does not exist, creating a new one", localRepo.getDirectory()); localRepo.create(); } git = new Git(localRepo); } @Override - public synchronized void save(Note note, AuthenticationInfo subject) throws IOException { - super.save(note, subject); + public void move(String noteId, + String notePath, + String newNotePath, + AuthenticationInfo subject) throws IOException { + super.move(noteId, notePath, newNotePath, subject); + String noteFileName = buildNoteFileName(noteId, notePath); + String newNoteFileName = buildNoteFileName(noteId, newNotePath); + git.rm().addFilepattern(noteFileName); + git.add().addFilepattern(newNoteFileName); + try { + git.commit().setMessage("Move note " + noteId + " from " + noteFileName + " to " + + newNoteFileName).call(); + } catch (GitAPIException e) { + throw new IOException(e); + } + } + + @Override + public void move(String folderPath, String newFolderPath, + AuthenticationInfo subject) throws IOException { + super.move(folderPath, newFolderPath, subject); + git.rm().addFilepattern(folderPath.substring(1)); + git.add().addFilepattern(newFolderPath.substring(1)); + try { + git.commit().setMessage("Move folder " + folderPath + " to " + newFolderPath).call(); + } catch (GitAPIException e) { + throw new IOException(e); + } } /* implemented as git add+commit - * @param pattern is the noteId + * @param noteId is the noteId + * @param noteName name of the note * @param commitMessage is a commit message (checkpoint message) * (non-Javadoc) * @see org.apache.zeppelin.notebook.repo.VFSNotebookRepo#checkpoint(String, String) */ @Override - public Revision checkpoint(String pattern, String commitMessage, AuthenticationInfo subject) { + public Revision checkpoint(String noteId, + String notePath, + String commitMessage, + AuthenticationInfo subject) throws IOException { + String noteFileName = buildNoteFileName(noteId, notePath); Revision revision = Revision.EMPTY; try { List<DiffEntry> gitDiff = git.diff().call(); if (!gitDiff.isEmpty()) { - LOG.debug("Changes found for pattern '{}': {}", pattern, gitDiff); - DirCache added = git.add().addFilepattern(pattern).call(); - LOG.debug("{} changes are about to be commited", added.getEntryCount()); + LOGGER.debug("Changes found for pattern '{}': {}", noteFileName, gitDiff); + DirCache added = git.add().addFilepattern(noteFileName).call(); + LOGGER.debug("{} changes are about to be commited", added.getEntryCount()); RevCommit commit = git.commit().setMessage(commitMessage).call(); revision = new Revision(commit.getName(), commit.getShortMessage(), commit.getCommitTime()); } else { - LOG.debug("No changes found {}", pattern); + LOGGER.debug("No changes found {}", noteFileName); } } catch (GitAPIException e) { - LOG.error("Failed to add+commit {} to Git", pattern, e); + LOGGER.error("Failed to add+commit {} to Git", noteFileName, e); } return revision; } @@ -124,63 +154,70 @@ public class GitNotebookRepo extends VFSNotebookRepo implements NotebookRepoWith * 4. apply stash on top and remove it */ @Override - public synchronized Note get(String noteId, String revId, AuthenticationInfo subject) - throws IOException { + public synchronized Note get(String noteId, + String notePath, + String revId, + AuthenticationInfo subject) throws IOException { Note note = null; RevCommit stash = null; + String noteFileName = buildNoteFileName(noteId, notePath); try { - List<DiffEntry> gitDiff = git.diff().setPathFilter(PathFilter.create(noteId)).call(); + List<DiffEntry> gitDiff = git.diff().setPathFilter(PathFilter.create(noteFileName)).call(); boolean modified = !gitDiff.isEmpty(); if (modified) { // stash changes stash = git.stashCreate().call(); Collection<RevCommit> stashes = git.stashList().call(); - LOG.debug("Created stash : {}, stash size : {}", stash, stashes.size()); + LOGGER.debug("Created stash : {}, stash size : {}", stash, stashes.size()); } ObjectId head = git.getRepository().resolve(Constants.HEAD); // checkout to target revision - git.checkout().setStartPoint(revId).addPath(noteId).call(); + git.checkout().setStartPoint(revId).addPath(noteFileName).call(); // get the note - note = super.get(noteId, subject); + note = super.get(noteId, notePath, subject); // checkout back to head - git.checkout().setStartPoint(head.getName()).addPath(noteId).call(); + git.checkout().setStartPoint(head.getName()).addPath(noteFileName).call(); if (modified && stash != null) { // unstash changes ObjectId applied = git.stashApply().setStashRef(stash.getName()).call(); ObjectId dropped = git.stashDrop().setStashRef(0).call(); Collection<RevCommit> stashes = git.stashList().call(); - LOG.debug("Stash applied as : {}, and dropped : {}, stash size: {}", applied, dropped, + LOGGER.debug("Stash applied as : {}, and dropped : {}, stash size: {}", applied, dropped, stashes.size()); } } catch (GitAPIException e) { - LOG.error("Failed to return note from revision \"{}\"", revId, e); + LOGGER.error("Failed to return note from revision \"{}\"", revId, e); } return note; } @Override - public List<Revision> revisionHistory(String noteId, AuthenticationInfo subject) { + public List<Revision> revisionHistory(String noteId, + String notePath, + AuthenticationInfo subject) throws IOException { List<Revision> history = Lists.newArrayList(); - LOG.debug("Listing history for {}:", noteId); + String noteFileName = buildNoteFileName(noteId, notePath); + LOGGER.debug("Listing history for {}:", noteFileName); try { - Iterable<RevCommit> logs = git.log().addPath(noteId).call(); + Iterable<RevCommit> logs = git.log().addPath(noteFileName).call(); for (RevCommit log: logs) { history.add(new Revision(log.getName(), log.getShortMessage(), log.getCommitTime())); - LOG.debug(" - ({},{},{})", log.getName(), log.getCommitTime(), log.getFullMessage()); + LOGGER.debug(" - ({},{},{})", log.getName(), log.getCommitTime(), log.getFullMessage()); } } catch (NoHeadException e) { //when no initial commit exists - LOG.warn("No Head found for {}, {}", noteId, e.getMessage()); + LOGGER.warn("No Head found for {}, {}", noteFileName, e.getMessage()); } catch (GitAPIException e) { - LOG.error("Failed to get logs for {}", noteId, e); + LOGGER.error("Failed to get logs for {}", noteFileName, e); } return history; } @Override - public Note setNoteRevision(String noteId, String revId, AuthenticationInfo subject) + public Note setNoteRevision(String noteId, String noteName, String revId, + AuthenticationInfo subject) throws IOException { - Note revisionNote = get(noteId, revId, subject); + Note revisionNote = get(noteId, noteName, revId, subject); if (revisionNote != null) { save(revisionNote, subject); } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/085efeb6/zeppelin-plugins/notebookrepo/git/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-plugins/notebookrepo/git/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java b/zeppelin-plugins/notebookrepo/git/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java index 58d7cc1..6c30e42 100644 --- a/zeppelin-plugins/notebookrepo/git/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java +++ b/zeppelin-plugins/notebookrepo/git/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java @@ -51,6 +51,8 @@ public class GitNotebookRepoTest { private static final String TEST_NOTE_ID = "2A94M5J1Z"; private static final String TEST_NOTE_ID2 = "2A94M5J2Z"; + private static final String TEST_NOTE_PATH = "/my_project/my_note1"; + private static final String TEST_NOTE_PATH2 = "/my_project/my_note2"; private File zeppelinDir; private String notebooksDir; @@ -68,23 +70,9 @@ public class GitNotebookRepoTest { File notebookDir = new File(notebooksDir); notebookDir.mkdirs(); - String testNoteDir = Joiner.on(File.separator).join(notebooksDir, TEST_NOTE_ID); - String testNoteDir2 = Joiner.on(File.separator).join(notebooksDir, TEST_NOTE_ID2); FileUtils.copyDirectory( - new File( - GitNotebookRepoTest.class.getResource( - Joiner.on(File.separator).join("", TEST_NOTE_ID) - ).getFile() - ), - new File(testNoteDir)); - FileUtils.copyDirectory( - new File( - GitNotebookRepoTest.class.getResource( - Joiner.on(File.separator).join("", TEST_NOTE_ID2) - ).getFile() - ), - new File(testNoteDir2) - ); + new File(GitNotebookRepoTest.class.getResource("/notebook").getFile()), + new File(notebooksDir)); System.setProperty(ConfVars.ZEPPELIN_HOME.getVarName(), zeppelinDir.getAbsolutePath()); System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_DIR.getVarName(), notebookDir.getAbsolutePath()); @@ -128,7 +116,7 @@ public class GitNotebookRepoTest { assertThat(notebookRepo.list(null)).isNotEmpty(); //when - List<Revision> testNotebookHistory = notebookRepo.revisionHistory(TEST_NOTE_ID, null); + List<Revision> testNotebookHistory = notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null); //then //no initial commit, empty history @@ -142,17 +130,17 @@ public class GitNotebookRepoTest { assertThat(notebookRepo.list(null)).isNotEmpty(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID2)).isTrue(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, TEST_NOTE_PATH2, null)).isEmpty(); //add commit to both notes - notebookRepo.checkpoint(TEST_NOTE_ID, "first commit, note1", null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(1); - notebookRepo.checkpoint(TEST_NOTE_ID2, "first commit, note2", null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null).size()).isEqualTo(1); + notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "first commit, note1", null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(1); + notebookRepo.checkpoint(TEST_NOTE_ID2, TEST_NOTE_PATH2, "first commit, note2", null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, TEST_NOTE_PATH2, null).size()).isEqualTo(1); //modify, save and checkpoint first note - Note note = notebookRepo.get(TEST_NOTE_ID, null); + Note note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); Map<String, Object> config = p.getConfig(); @@ -160,15 +148,15 @@ public class GitNotebookRepoTest { p.setConfig(config); p.setText("%md note1 test text"); notebookRepo.save(note, null); - assertThat(notebookRepo.checkpoint(TEST_NOTE_ID, "second commit, note1", null)).isNotNull(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(2); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null).size()).isEqualTo(1); - assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, "first commit, note2", null)) + assertThat(notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "second commit, note1", null)).isNotNull(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(2); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, TEST_NOTE_PATH2, null).size()).isEqualTo(1); + assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, TEST_NOTE_PATH2, "first commit, note2", null)) .isEqualTo(Revision.EMPTY); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null).size()).isEqualTo(1); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, TEST_NOTE_PATH2, null).size()).isEqualTo(1); //modify, save and checkpoint second note - note = notebookRepo.get(TEST_NOTE_ID2, null); + note = notebookRepo.get(TEST_NOTE_ID2, TEST_NOTE_PATH2, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); config = p.getConfig(); @@ -176,9 +164,9 @@ public class GitNotebookRepoTest { p.setConfig(config); p.setText("%md note2 test text"); notebookRepo.save(note, null); - assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, "second commit, note2", null)).isNotNull(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(2); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null).size()).isEqualTo(2); + assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, TEST_NOTE_PATH2, "second commit, note2", null)).isNotNull(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(2); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, TEST_NOTE_PATH2, null).size()).isEqualTo(2); } @Test @@ -187,15 +175,15 @@ public class GitNotebookRepoTest { notebookRepo = new GitNotebookRepo(conf); assertThat(notebookRepo.list(null)).isNotEmpty(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isEmpty(); - notebookRepo.checkpoint(TEST_NOTE_ID, "first commit", null); - List<Revision> notebookHistoryBefore = notebookRepo.revisionHistory(TEST_NOTE_ID, null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isNotEmpty(); + notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "first commit", null); + List<Revision> notebookHistoryBefore = notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isNotEmpty(); int initialCount = notebookHistoryBefore.size(); // add changes to note - Note note = notebookRepo.get(TEST_NOTE_ID, null); + Note note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); Map<String, Object> config = p.getConfig(); @@ -205,15 +193,15 @@ public class GitNotebookRepoTest { // save and checkpoint note notebookRepo.save(note, null); - notebookRepo.checkpoint(TEST_NOTE_ID, "second commit", null); + notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "second commit", null); // see if commit is added - List<Revision> notebookHistoryAfter = notebookRepo.revisionHistory(TEST_NOTE_ID, null); + List<Revision> notebookHistoryAfter = notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null); assertThat(notebookHistoryAfter.size()).isEqualTo(initialCount + 1); } - private boolean containsNote(List<NoteInfo> notes, String noteId) { - for (NoteInfo note: notes) { + private boolean containsNote(Map<String, NoteInfo> notes, String noteId) { + for (NoteInfo note: notes.values()) { if (note.getId().equals(noteId)) { return true; } @@ -227,15 +215,15 @@ public class GitNotebookRepoTest { notebookRepo = new GitNotebookRepo(conf); assertThat(notebookRepo.list(null)).isNotEmpty(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isEmpty(); // add first checkpoint - Revision revision_1 = notebookRepo.checkpoint(TEST_NOTE_ID, "first commit", null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(1); - int paragraphCount_1 = notebookRepo.get(TEST_NOTE_ID, null).getParagraphs().size(); + Revision revision_1 = notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "first commit", null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(1); + int paragraphCount_1 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null).getParagraphs().size(); // add paragraph and save - Note note = notebookRepo.get(TEST_NOTE_ID, null); + Note note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); Map<String, Object> config = p1.getConfig(); @@ -245,17 +233,17 @@ public class GitNotebookRepoTest { notebookRepo.save(note, null); // second checkpoint - notebookRepo.checkpoint(TEST_NOTE_ID, "second commit", null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(2); - int paragraphCount_2 = notebookRepo.get(TEST_NOTE_ID, null).getParagraphs().size(); + notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "second commit", null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(2); + int paragraphCount_2 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null).getParagraphs().size(); assertThat(paragraphCount_2).isEqualTo(paragraphCount_1 + 1); // get note from revision 1 - Note noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, revision_1.id, null); + Note noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, revision_1.id, null); assertThat(noteRevision_1.getParagraphs().size()).isEqualTo(paragraphCount_1); // get current note - note = notebookRepo.get(TEST_NOTE_ID, null); + note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_2); @@ -265,17 +253,17 @@ public class GitNotebookRepoTest { p2.setConfig(config); p2.setText("get revision when modified note test text"); notebookRepo.save(note, null); - note = notebookRepo.get(TEST_NOTE_ID, null); + note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); int paragraphCount_3 = note.getParagraphs().size(); assertThat(paragraphCount_3).isEqualTo(paragraphCount_2 + 1); // get revision 1 again - noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, revision_1.id, null); + noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, revision_1.id, null); assertThat(noteRevision_1.getParagraphs().size()).isEqualTo(paragraphCount_1); // check that note is unchanged - note = notebookRepo.get(TEST_NOTE_ID, null); + note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_3); } @@ -285,15 +273,15 @@ public class GitNotebookRepoTest { notebookRepo = new GitNotebookRepo(conf); assertThat(notebookRepo.list(null)).isNotEmpty(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isEmpty(); // add first checkpoint - Revision revision_1 = notebookRepo.checkpoint(TEST_NOTE_ID, "first commit", null); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(1); - int paragraphCount_1 = notebookRepo.get(TEST_NOTE_ID, null).getParagraphs().size(); + Revision revision_1 = notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "first commit", null); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(1); + int paragraphCount_1 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null).getParagraphs().size(); // get current note - Note note = notebookRepo.get(TEST_NOTE_ID, null); + Note note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_1); @@ -307,17 +295,17 @@ public class GitNotebookRepoTest { int paragraphCount_2 = note.getParagraphs().size(); // get note from revision 1 - Note noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, revision_1.id, null); + Note noteRevision_1 = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, revision_1.id, null); assertThat(noteRevision_1.getParagraphs().size()).isEqualTo(paragraphCount_1); // get current note - note = notebookRepo.get(TEST_NOTE_ID, null); + note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_2); // test for absent revision Revision absentRevision = new Revision("absentId", StringUtils.EMPTY, 0); - note = notebookRepo.get(TEST_NOTE_ID, absentRevision.id, null); + note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, absentRevision.id, null); assertThat(note).isNull(); } @@ -327,19 +315,19 @@ public class GitNotebookRepoTest { notebookRepo = new GitNotebookRepo(conf); assertThat(notebookRepo.list(null)).isNotEmpty(); assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty(); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null)).isEmpty(); // get current note - Note note = notebookRepo.get(TEST_NOTE_ID, null); + Note note = notebookRepo.get(TEST_NOTE_ID, TEST_NOTE_PATH, null); note.setInterpreterFactory(mock(InterpreterFactory.class)); int paragraphCount_1 = note.getParagraphs().size(); LOG.info("initial paragraph count: {}", paragraphCount_1); // checkpoint revision1 - Revision revision1 = notebookRepo.checkpoint(TEST_NOTE_ID, "set revision: first commit", null); + Revision revision1 = notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "set revision: first commit", null); //TODO(khalid): change to EMPTY after rebase assertThat(revision1).isNotNull(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(1); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(1); // add one more paragraph and save Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); @@ -353,33 +341,33 @@ public class GitNotebookRepoTest { LOG.info("paragraph count after modification: {}", paragraphCount_2); // checkpoint revision2 - Revision revision2 = notebookRepo.checkpoint(TEST_NOTE_ID, "set revision: second commit", null); + Revision revision2 = notebookRepo.checkpoint(TEST_NOTE_ID, TEST_NOTE_PATH, "set revision: second commit", null); //TODO(khalid): change to EMPTY after rebase assertThat(revision2).isNotNull(); - assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null).size()).isEqualTo(2); + assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, TEST_NOTE_PATH, null).size()).isEqualTo(2); // set note to revision1 - Note returnedNote = notebookRepo.setNoteRevision(note.getId(), revision1.id, null); + Note returnedNote = notebookRepo.setNoteRevision(note.getId(), note.getPath(), revision1.id, null); assertThat(returnedNote).isNotNull(); assertThat(returnedNote.getParagraphs().size()).isEqualTo(paragraphCount_1); // check note from repo - Note updatedNote = notebookRepo.get(note.getId(), null); + Note updatedNote = notebookRepo.get(note.getId(), note.getPath(), null); assertThat(updatedNote).isNotNull(); assertThat(updatedNote.getParagraphs().size()).isEqualTo(paragraphCount_1); // set back to revision2 - returnedNote = notebookRepo.setNoteRevision(note.getId(), revision2.id, null); + returnedNote = notebookRepo.setNoteRevision(note.getId(), note.getPath(), revision2.id, null); assertThat(returnedNote).isNotNull(); assertThat(returnedNote.getParagraphs().size()).isEqualTo(paragraphCount_2); // check note from repo - updatedNote = notebookRepo.get(note.getId(), null); + updatedNote = notebookRepo.get(note.getId(), note.getPath(), null); assertThat(updatedNote).isNotNull(); assertThat(updatedNote.getParagraphs().size()).isEqualTo(paragraphCount_2); // try failure case - set to invalid revision - returnedNote = notebookRepo.setNoteRevision(note.getId(), "nonexistent_id", null); + returnedNote = notebookRepo.setNoteRevision(note.getId(), note.getPath(), "nonexistent_id", null); assertThat(returnedNote).isNull(); } }