Skip to content

Commit

Permalink
adds readme to repositoy
Browse files Browse the repository at this point in the history
  • Loading branch information
James Morley committed Jan 9, 2023
1 parent 1c92da8 commit 6ab83c6
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 42 deletions.
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
# LibraryNB

## Description
LibraryNB is a cross platform application that provides a convenient way to import and run git repositories of Jupyter Notebooks on your local machine. It handles the process of cloning the repository, creating the Conda environment, and launching Jupyter Lab in a desktop environment on your system. It currently runs on only Windows and Linux.

## Installation
### Prerequisites

LibraryNB assumes you have git configured and installed on your computer. It also assumes that you have either Conda or Mamba installed on your system. Mamba is currently recommended. Conda has not been tested.

### Linux
Start by acquiring the deb or rpm package, depending on your systems package manager, from the release section of this repository. Then run
```bash
sudo apt install ./librarynb_{version}_{arch}.{ext}
```
in the directory where you downloaded the package.

### First run
When ran the first time LibraryNB will ask you a few questions to configure itself to your system. Once you have answered the questions and pressed "Save", LibraryNB will exit and will be ready to use.

## Security
LibraryNB makes no attempt to determine the trustworthiness of Jupyter Notebooks or Conda environments specified in git repositories. You should never use LibraryNB on git repositories you don't trust.

## Current State
This software is very early in its development. It should not be considered secure or stable at this time. Use at your own risk.

## Development
Please feel free to create an issue for any problem you encounter using this software. Pull requests are welcome.

### Direction for the future
Current development focuses on bringing LibraryNB to more platforms and increasing the stability of the application.

### Design Decisions
LibraryNB does not use containers to provide consistent environments to run Jupyter Notebooks. It instead uses just Conda or Mamba to create virtual environments.

Additionaly LibraryNB does not impose a specific git workflow upon the user. LibraryNB only clones repositories. git should work like normal on the cloned repository.

### Integration with Jupyter Book

LibraryNB can read a "_config.yml" files in a repository to provide information about a repository to the user. This includes a title, author, thumbnail, logo, and copyright info.



## Installation

4 changes: 3 additions & 1 deletion main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const { createLibraryWindow, createJupyterWindow, createSetupWindow } = require(
const config = require("./src/config.js").getConfig();
const { registerProtocol } = require("./src/protocol.js");

if (require('electron-squirrel-startup')) return;
if (require('electron-squirrel-startup')) {
app.quit();
}

app.whenReady().then(() => {
if(! config) {
Expand Down
19 changes: 9 additions & 10 deletions src/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,18 @@ function bookFromConfig(config, projectDir) {

function loadBooks() {
let books = [];
let globPath = ''
if (os === 'win32') { //Glob only uses posix paths
let prefix = path.normalize(repoDir).replaceAll("\\", "/").substring(2);
globPath = path.posix.join(prefix, '*', '*', '*');
} else {
globPath = path.join(repoDir, '*', '*', '*');
}
let globPath = "";
if (os === "win32") { //Glob only uses posix paths
let prefix = path.normalize(repoDir).replaceAll("\\", "/").substring(2);
globPath = path.posix.join(prefix, "*", "*", "*");
} else {
globPath = path.join(repoDir, "*", "*", "*");
}
const projectDirs = glob.sync(globPath);
for (let i in projectDirs) {
let configFile = fs.readFileSync(path.join(projectDirs[i], "_config.yml"), "utf8");
const config = YAML.parse(configFile);
books.push(bookFromConfig(config, projectDirs[i]));
fs.closeSync(configFile);
}
return books;
}
Expand Down Expand Up @@ -222,13 +221,13 @@ async function launchBook(fullPath) {

//let output = "";
//for await (const chunk of launcher.stdout) {
//output += chunk;
//output += chunk;
//}
//let pid = parseInt(output.trim());

//let exitCode = await proc.endProcess(launcher);
//if (exitCode) {
//throw `launcher process exited with code ${exitCode}`;
//throw `launcher process exited with code ${exitCode}`;
//}

let jupyterUrl = await getJupyterUrl(fullPath);
Expand Down
28 changes: 14 additions & 14 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function getConfigPath() {
}

function validate(config) {
let errors = []
let errors = [];
if (errors.length === 0){
return {success: true};
} else {
Expand All @@ -20,43 +20,43 @@ function validate(config) {
}

function writeConfig(config) {
let results = validate(config)
let results = validate(config);
if (!results.success) {
return results
return results;
}
try {
fs.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2))
fs.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
} catch (error) {
throw `Unable to write to config file: ${error}`
throw `Unable to write to config file: ${error}`;
}
return results;
}

function createConfig(config) {
if (!configExists()) {
let configPath = getConfigPath()
let directory = path.dirname(configPath)
let configPath = getConfigPath();
let directory = path.dirname(configPath);
if (! fs.existsSync(directory)){
if (!fs.mkdirSync(directory, { recursive: true })) {
throw "Config directory does not exist and unable to create it"
if (!fs.mkdirSync(directory, { recursive: true })) {
throw "Config directory does not exist and unable to create it";
}
}
}
return writeConfig(config)
return writeConfig(config);
}

function addToWhiteList(url) {
if (!url || typeof url != "string") {
throw "url must be a string";
}
let config = getConfig();
if (! whiteList in config){
if (!("whiteList" in config)){
config.whiteList = [url];
} else {
config.whiteList.push(url)
config.whiteList.push(url);
}
writeConfig(config)
return true
writeConfig(config);
return true;
}

function configExists() {
Expand Down
10 changes: 5 additions & 5 deletions src/proc.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function endProcess(process){
function getShell() {
if (os === "linux"){
return "/bin/bash";
} else if (os === 'win32') {
} else if (os === "win32") {
return true;
} else {
throw "Coming soon to other operating systems";
Expand All @@ -80,7 +80,7 @@ function getShell() {
function getLaunchScript() {
if (os === "linux") {
return linuxSetupScript + linuxLaunchScript;
} else if(os === 'win32'){
} else if(os === "win32"){
return winCondaSetup + winLaunchScript;
} else {
throw "Coming soon to other operating systems";
Expand All @@ -90,7 +90,7 @@ function getLaunchScript() {
function getListScript() {
if (os === "linux") {
return linuxSetupScript + linuxListScript;
} else if(os === 'win32'){
} else if(os === "win32"){
return winCondaSetup + winListScript;
} else {
throw "Coming soon to other operating systems";
Expand All @@ -100,7 +100,7 @@ function getListScript() {
function getEnvScript() {
if (os === "linux") {
return linuxSetupScript + linuxEnvScript;
} else if(os === 'win32'){
} else if(os === "win32"){
return winCondaSetup + winEnvScript;
} else {
throw "Coming soon to other operating systems";
Expand All @@ -110,7 +110,7 @@ function getEnvScript() {
function getRemoveScript() {
if(os === "linux") {
return linuxSetupScript + linuxRemoveScript;
} else if(os === 'win32'){
} else if(os === "win32"){
return winCondaSetup + winRemoveScript;
} else {
throw "Coming soon to other operating systems";
Expand Down
22 changes: 11 additions & 11 deletions src/windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async function createJupyterWindow (url) {
const jupyter = await launchBook(fullPath);
jupyterWindow.loadURL(jupyter.url);
jupyterWindow.on("close", function(){
jupyter.server.kill()
jupyter.server.kill();
jupyterWindow = null;
});
}
Expand All @@ -81,6 +81,10 @@ async function createLibraryWindow() {
return { action: "deny" };
});

ipcMain.on("launch-book", (event, url) => {
createJupyterWindow(url);
});

ipcMain.on("open-repo", (e, url) => {
shell.openExternal(url);
});
Expand Down Expand Up @@ -115,10 +119,6 @@ async function createLibraryWindow() {
let books = loadBooks(path.join(repoDir));
win.webContents.send("load-books", books);
});

ipcMain.on("launch-book", (event, url) => {
createJupyterWindow(url);
});
}

function createSetupWindow() {
Expand All @@ -134,12 +134,12 @@ function createSetupWindow() {
});

ipcMain.on("save", (event, config) => {
let results = createConfig(config)
if (results.success){
win.close();
} else {
win.webContents.send('display-errors', results.errors);
}
let results = createConfig(config);
if (results.success){
win.close();
} else {
win.webContents.send("display-errors", results.errors);
}
});

ipcMain.handle("dialog:selectDir", async () => {
Expand Down

0 comments on commit 6ab83c6

Please sign in to comment.