From 9f3c969555ca5e7f57afcc2d1ac79757ff59d3e5 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Fri, 17 May 2024 15:45:46 +0300 Subject: [PATCH 1/8] Apply maven build setup --- .gitignore | 8 +- .../resources => assembly/zip}/install.py | 0 .../resources => assembly/zip}/kernel.json | 2 +- assembly/zip/zip.xml | 24 ++ build.gradle | 129 --------- buildSrc/build.gradle | 13 - .../gradle/DeclaredModuleInfo.groovy | 7 - .../gradle/InventoryReportRenderer.groovy | 91 ------ .../NewInventoryHtmlReportRenderer.groovy | 267 ------------------ .../resources/license-report.template.css | 151 ---------- .../resources/license-report.template.html | 71 ----- gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 244 ---------------- gradlew.bat | 92 ------ pom.xml | 138 +++++++++ settings.gradle | 1 - .../ijava/execution/IJavaLoaderDelegate.java | 3 +- 18 files changed, 170 insertions(+), 1077 deletions(-) rename {buildSrc/src/main/resources => assembly/zip}/install.py (100%) rename {buildSrc/src/main/resources => assembly/zip}/kernel.json (80%) create mode 100644 assembly/zip/zip.xml delete mode 100644 build.gradle delete mode 100644 buildSrc/build.gradle delete mode 100644 buildSrc/src/main/groovy/io/github/spencerpark/gradle/DeclaredModuleInfo.groovy delete mode 100644 buildSrc/src/main/groovy/io/github/spencerpark/gradle/InventoryReportRenderer.groovy delete mode 100644 buildSrc/src/main/groovy/io/github/spencerpark/gradle/NewInventoryHtmlReportRenderer.groovy delete mode 100644 buildSrc/src/main/resources/license-report.template.css delete mode 100644 buildSrc/src/main/resources/license-report.template.html delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat create mode 100644 pom.xml delete mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index 897f432..b2339c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -.gradle/ .idea/ -build/ -out/ \ No newline at end of file +target/ +.classpath +.project +.settings +*.iml diff --git a/buildSrc/src/main/resources/install.py b/assembly/zip/install.py similarity index 100% rename from buildSrc/src/main/resources/install.py rename to assembly/zip/install.py diff --git a/buildSrc/src/main/resources/kernel.json b/assembly/zip/kernel.json similarity index 80% rename from buildSrc/src/main/resources/kernel.json rename to assembly/zip/kernel.json index 14b11df..c3de95c 100644 --- a/buildSrc/src/main/resources/kernel.json +++ b/assembly/zip/kernel.json @@ -4,7 +4,7 @@ "--add-opens", "jdk.jshell/jdk.jshell=ALL-UNNAMED", "-jar", - "@KERNEL_INSTALL_DIRECTORY@/@JAR_FILE@", + "@KERNEL_INSTALL_DIRECTORY@/${project.build.finalName}.jar", "{connection_file}" ], "display_name": "Java", diff --git a/assembly/zip/zip.xml b/assembly/zip/zip.xml new file mode 100644 index 0000000..460bca6 --- /dev/null +++ b/assembly/zip/zip.xml @@ -0,0 +1,24 @@ + + zip + + zip + + false + + + ${project.build.directory}/${project.build.finalName}.jar + java + + + assembly/zip/kernel.json + java + true + + + assembly/zip/install.py + / + + + diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 7d43a13..0000000 --- a/build.gradle +++ /dev/null @@ -1,129 +0,0 @@ -plugins { - id 'java' - id 'maven-publish' - id('com.github.hierynomus.license') version '0.16.1' - id('com.github.jk1.dependency-license-report') -} - -import org.apache.tools.ant.filters.ReplaceTokens -import com.github.jk1.license.render.* -import com.github.jk1.license.filter.* -import io.github.spencerpark.gradle.* - -group = 'io.github.spencerpark' -version = '1.0-M2' - -wrapper { - gradleVersion = '8.5' - distributionType = Wrapper.DistributionType.ALL -} - -// Add the license header to source files -license { - header = file('LICENSE') - exclude '**/*.json' - mapping { - // Use a regular multiline comment rather than a javadoc comment - java = 'SLASHSTAR_STYLE' - } -} -build.dependsOn 'licenseFormat' - -// Configures the license report generated for the dependencies. -licenseReport { - excludeGroups = [] - renderers = [ - // Generate a pretty HTML report that groups dependencies by their license. - new NewInventoryHtmlReportRenderer('dependencies.html'), - // TODO make sure ci verifies that all licenses are know to be allowed to redistribute before publishing - new JsonReportRenderer('dependencies.json') - ] - - // Group same licenses despite names being slightly different (ex. Apache 2.0 vs Apache version 2) - filters = [new LicenseBundleNormalizer()] - - configurations = ['compile'] -} - -compileJava { - sourceCompatibility = 11 - targetCompatibility = 11 -} - -configurations { - shade - // transitive true to make sure that the dependencies of shade dependencies also get shaded into the jar - shade.transitive = true - implementation.extendsFrom(shade) -} - -repositories { - mavenCentral() - maven { - url = 'https://oss.sonatype.org/content/repositories/snapshots/' - } - mavenLocal() -} - -dependencies { - shade group: 'io.github.spencerpark', name: 'jupyter-jvm-basekernel', version: '2.3.0' - - shade group: 'org.apache.ivy', name: 'ivy', version: '2.5.2' - //shade group: 'org.apache.maven', name: 'maven-settings-builder', version: '3.6.0' - shade group: 'org.apache.maven', name: 'maven-model-builder', version: '3.6.0' - - testImplementation group: 'junit', name: 'junit', version: '4.13.1' -} - -jar { - //Include all shaded dependencies in the jar - from configurations.shade - .collect { it.isDirectory() ? it : zipTree(it) } - - manifest { - attributes('Main-class': 'io.github.spencerpark.ijava.IJava') - } - - duplicatesStrategy = 'include' -} - -processResources { - def tokens = [ - 'version': project.version, - 'project': project.name - ] - inputs.properties(tokens) - filter ReplaceTokens, tokens: tokens -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - } - } -} - -tasks.register('zipKernel', Zip) { - group = 'distribution' - description = 'Zips jupyter kernel jar with its installation script.' - - into(".", { - // copy as is install script - from(file('buildSrc/src/main/resources/install.py')) - }) - - into("java", { - // copy jar - from(jar.archiveFile) - - // preprocess kernel.json - def kernelSpecTemplate = file('buildSrc/src/main/resources/kernel.json') - from(kernelSpecTemplate) { - include kernelSpecTemplate.name - filter { line -> line.replaceAll('@JAR_FILE@', "${project.name}-${project.version}.jar") } - } - }) -} - -zipKernel.dependsOn 'jar', 'generateLicenseReport' \ No newline at end of file diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index 2891fa9..0000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -plugins { - id 'groovy' -} - -repositories { - maven { - url = 'https://plugins.gradle.org/m2/' - } -} - -dependencies { - implementation group: 'com.github.jk1.dependency-license-report', name: 'com.github.jk1.dependency-license-report.gradle.plugin', version: '1.1' -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/DeclaredModuleInfo.groovy b/buildSrc/src/main/groovy/io/github/spencerpark/gradle/DeclaredModuleInfo.groovy deleted file mode 100644 index 4216c1a..0000000 --- a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/DeclaredModuleInfo.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.spencerpark.gradle - -class DeclaredModuleInfo { - String projectUrl - String license - String licenseUrl -} diff --git a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/InventoryReportRenderer.groovy b/buildSrc/src/main/groovy/io/github/spencerpark/gradle/InventoryReportRenderer.groovy deleted file mode 100644 index a15d2bb..0000000 --- a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/InventoryReportRenderer.groovy +++ /dev/null @@ -1,91 +0,0 @@ -package io.github.spencerpark.gradle - -import com.github.jk1.license.* -import groovy.json.JsonParserType -import groovy.json.JsonSlurper - -abstract class InventoryReportRenderer { - /** - * Collect declared from a JSON object with maven coordinates as keys and {@link DeclaredModuleInfo} - * as values - * @param declarations the stream to parse the json object from - * @return the collected declarations - */ - static Map parseDeclarations(InputStream declarations) { - def rawDeclarations = new JsonSlurper() - .setType(JsonParserType.LAX) - .parse(declarations) - - assert rawDeclarations instanceof Map: "Declaration spec must be a json object" - - return rawDeclarations.collectEntries([:]) { coords, spec -> - assert spec instanceof Map: "Declaration spec for $coords is not an object" - - DeclaredModuleInfo info = new DeclaredModuleInfo() - spec.forEach { String key, val -> - assert val instanceof String: "Declaration spec for $coords::$key must be a string" - assert info.hasProperty(key), "Declaration spec for $coords has unknown key $key" - - info[key] = val - } - assert info.projectUrl: "Declaration missing required key: projectUrl" - assert info.license: "Declaration missing required key: license" - assert info.licenseUrl: "Declaration missing required key: licenseUrl" - - return [(coords): info] - } - } - - static Map> collectModulesByLicenseName(ProjectData data, Map declared) { - Map> modulesByLicense = [:] - - def addModule = { String licenseName, ModuleData module -> - String coords = module.with { "$group:$name:$version" } - - if (licenseName == "Unknown" && declared.containsKey(coords)) - licenseName = declared[coords].license - - modulesByLicense.compute(licenseName) { k, modules -> - return (modules ?: []) << module - } - } - - data.allDependencies.each { module -> - if (module.poms.isEmpty()) { - addModule(module.licenseFiles.isEmpty() ? "Unknown" : "Embedded", module) - return - } - - PomData pom = module.poms.first() - if (pom.licenses.isEmpty()) { - addModule(module.licenseFiles.isEmpty() ? "Unknown" : "Embedded", module) - } else { - pom.licenses.each { License license -> - addModule(license.name, module) - } - } - } - - return modulesByLicense - } - - // imported modules are things declared as dependencies but not actually included via gradle means. For - // example a javascript dependency. - static Map>> collectModulesByLicenseFromImported(ProjectData data) { - Map>> externalByModulesByLicense = [:] - - data.importedModules.each { ImportedModuleBundle module -> - Map> modulesByLicense = [:] - - module.modules.each { ImportedModuleData moduleData -> - modulesByLicense.compute(moduleData.license) { k, modules -> - return (modules ?: []) << moduleData - } - } - - externalByModulesByLicense[module.name] = modulesByLicense - } - - return externalByModulesByLicense - } -} diff --git a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/NewInventoryHtmlReportRenderer.groovy b/buildSrc/src/main/groovy/io/github/spencerpark/gradle/NewInventoryHtmlReportRenderer.groovy deleted file mode 100644 index 5182943..0000000 --- a/buildSrc/src/main/groovy/io/github/spencerpark/gradle/NewInventoryHtmlReportRenderer.groovy +++ /dev/null @@ -1,267 +0,0 @@ -package io.github.spencerpark.gradle - -import com.github.jk1.license.* -import com.github.jk1.license.render.ReportRenderer -import groovy.text.SimpleTemplateEngine -import groovy.text.StreamingTemplateEngine - -class NewInventoryHtmlReportRenderer implements ReportRenderer { - private final String name - private final String fileName - private final Map declared - private final Map colors = [ - accent : '#F37726', - primary : 'white', - accentBg : '#616262', - primaryBg: '#989798', - darkText : '#4E4E4E', - lightText: '#e8e5e5', - ] - - private Writer output - private int counter - - NewInventoryHtmlReportRenderer(String fileName = 'index.html', String name = null, File declarationsFileName = null, Map colors = [:]) { - this.name = name - this.fileName = fileName - - if (declarationsFileName) - declared = InventoryReportRenderer.parseDeclarations(declarationsFileName.newInputStream()) - else - declared = [:] - - this.colors.putAll(colors) - } - - @Override - void render(ProjectData data) { - this.counter = 0 - - def project = data.project - def name = project.name - LicenseReportExtension config = project.licenseReport - def outFile = new File(config.outputDir, fileName) - - def stylesheet = NewInventoryHtmlReportRenderer.class.getResourceAsStream("/license-report.template.css").withReader { - new SimpleTemplateEngine() - .createTemplate(it) - .make(this.colors) - .writeTo(new StringWriter()) - .toString() - } - def template = NewInventoryHtmlReportRenderer.class.getResourceAsStream("/license-report.template.html").withReader { - new StreamingTemplateEngine().createTemplate(it) - } - - def binding = [ - stylesheet : stylesheet, - name : name, - project : project, - inventory : InventoryReportRenderer.collectModulesByLicenseName(data, declared), - externalInventories : InventoryReportRenderer.collectModulesByLicenseFromImported(data), - serializeHref : { String... values -> - values.findAll { it != null }.collect { it.replaceAll(/\s/, '_') }.join('_') - }, - printDependency : this.&printDependency, - printImportedDependency: this.&printImportedDependency, - ] - - outFile.withWriter { - template.make(binding).writeTo(it) - } - } - - void tag(Map attrs = [:], String name, def children) { - output << "<$name ${attrs.collect { k, v -> "$k=\"$v\"" }.join(" ")}>\n" - if (children.respondsTo("call")) - children.call() - else - text(children) - output << "\n" - } - - void div(Map attrs = [:], def children) { - tag(attrs, "div", children) - } - - void p(Map attrs = [:], def children) { - tag(attrs, "p", children) - } - - void a(Map attrs = [:], def children) { - tag(attrs, "a", children) - } - - void strong(Map attrs = [:], def children) { - tag(attrs, "strong", children) - } - - void ul(Map attrs = [:], def children) { - tag(attrs, "ul", children) - } - - void li(Map attrs = [:], def children) { - tag(attrs, "li", children) - } - - void text(def contents) { - if (contents != null) - output << String.valueOf(contents) - } - - void renderDependencyProperty(String label, def children) { - div(class: "dependency-prop") { - tag("label") { text(label) } - div(class: "dependency-value", children) - } - } - - void renderDependencyTitle(ModuleData data) { - p(class: "title") { - strong(class: "index", "${++counter}.") - - if (data.group) { - strong("Group: ") - text(data.group) - } - - if (data.name) { - strong("Name: ") - text(data.name) - } - - if (data.version) { - strong("Version: ") - text(data.version) - } - } - } - - void renderDependencyTitle(ImportedModuleData data) { - p(class: "title") { - strong(class: "index", ++counter) - - if (data.name) { - strong("Name: ") - text(data.name) - } - - if (data.version) { - strong("Version: ") - text(data.version) - } - } - } - - void renderDependencyProjectUrl(ModuleData data) { - String coords = data.with { "$group:$name:$version" } - - ManifestData manifest = data.manifests.isEmpty() ? null : data.manifests.first() - PomData pomData = data.poms.isEmpty() ? null : data.poms.first() - - if (manifest?.url && pomData?.projectUrl && manifest.url == pomData.projectUrl) { - renderDependencyProperty("Project URL") { - a(href: manifest.url, { text(manifest.url) }) - } - } else if (manifest?.url || pomData?.projectUrl) { - if (manifest?.url) { - renderDependencyProperty("Manifest Project URL") { - a(href: manifest.url, { text(manifest.url) }) - } - } - - if (pomData?.projectUrl) { - renderDependencyProperty("POM Project URL") { - a(href: pomData.projectUrl, { text(pomData.projectUrl) }) - } - } - } else if (declared.containsKey(coords)) { - renderDependencyProperty("Project URL") { - a(href: declared[coords].projectUrl, { text(declared[coords].projectUrl) }) - } - } - } - - void renderReferencedLicenses(ModuleData data) { - String coords = data.with { "$group:$name:$version" } - - ManifestData manifest = data.manifests.isEmpty() ? null : data.manifests.first() - PomData pomData = data.poms.isEmpty() ? null : data.poms.first() - - if (manifest?.license || pomData?.licenses) { - if (manifest?.license) { - if (manifest.license.startsWith("http")) { - renderDependencyProperty("Manifest license URL") { - a(href: manifest.license, { text(manifest.license) }) - } - } else if (manifest.hasPackagedLicense) { - renderDependencyProperty("Packaged License File") { - a(href: manifest.license, { text(manifest.url) }) - } - } else { - renderDependencyProperty("Manifest License") { - text("${manifest.license} (Not Packaged)") - } - } - } - - if (pomData?.licenses) { - pomData.licenses.each { License license -> - if (license.url) { - renderDependencyProperty("POM License") { - text("${license.name} - ") - if (license.url.startsWith("http")) - a(href: license.url, { text(license.url) }) - else - text(license.url) - } - } else { - renderDependencyProperty("POM License", { text(license.name) }) - } - } - } - } else if (declared.containsKey(coords)) { - renderDependencyProperty("License URL") { - a(href: declared[coords].licenseUrl, { text(declared[coords].license) }) - } - } - } - - void renderIncludedLicenses(ModuleData data) { - if (!data.licenseFiles.isEmpty() && !data.licenseFiles.first().fileDetails.isEmpty()) { - renderDependencyProperty("Embedded license files") { - ul { - data.licenseFiles.first().fileDetails.each { - def file = it.file - li { - a(href: file, { text(file) }) - } - } - } - } - } - } - - private void printDependency(Writer out, ModuleData data) { - this.output = out - div(class: "dependency") { - renderDependencyTitle(data) - renderDependencyProjectUrl(data) - renderReferencedLicenses(data) - renderIncludedLicenses(data) - } - } - - private printImportedDependency(Writer out, ImportedModuleData data) { - this.output = out - div(class: "dependency") { - renderDependencyTitle(data) - renderDependencyProperty("Project URL") { - a(href: data.projectUrl, { text(data.projectUrl) }) - } - renderDependencyProperty("License URL") { - a(href: data.licenseUrl, { text(data.license) }) - } - } - } -} diff --git a/buildSrc/src/main/resources/license-report.template.css b/buildSrc/src/main/resources/license-report.template.css deleted file mode 100644 index d6bbcdb..0000000 --- a/buildSrc/src/main/resources/license-report.template.css +++ /dev/null @@ -1,151 +0,0 @@ -@media print { - .inventory { - display: none; - } - - .content { - position: static !important; - } -} - -html, body, section { - height: 100%; -} - -body { - font-family: sans-serif; - line-height: 125%; - margin: 0; - background: $primaryBg; -} - -.header { - /* #22aa44 */ - background: $accent; - color: $darkText; - padding: 2em 1em 1em 1em; -} - -.header h1 { - font-size: 16pt; - margin: 0.5em 0; -} - -.header h2 { - font-size: 10pt; - margin: 0; -} - -.container { -} - -.inventory { - background: $accentBg; - color: $lightText; - padding: 0; - position: fixed; - left: 0; - top: 0; - height: 100%; - width: 25%; - overflow: auto; -} - -.inventory ul { - margin: 0; - padding: 0; -} - -.inventory li { - list-style: none; - padding: 0; - margin: 0; -} - -.inventory li a { - width: 100%; - box-sizing: border-box; - color: $lightText; - text-decoration: none; - display: flex; - flex-direction: row; - padding: 0.938em 0.750em; -} - -.inventory li a:hover { - background: rgba(50, 50, 50, 0.5); - color: white; -} - -.inventory .section-heading { - background: rgba(50, 50, 50, 0.25); - padding-left: 0.5em; - margin: 0; - padding-top: 1em; - padding-bottom: 1em; -} - -.license .license-name { - flex-grow: 1; -} - -.license .badge { - background: $accent; - padding: 0.625em 0.938em; - border-radius: 1.250em; - color: $darkText; - display: inline-table; -} - -.content { - padding: 0 1rem; - position: absolute; - top: 0; - bottom: 0; - left: 25%; - width: 75%; - box-sizing: border-box; -} - -.content h1 { - color: $darkText; - background-color: $accent; - padding: 0.67em; - margin: 0 -1rem; -} - -.dependency { - background: white; - padding: 1em; - margin-bottom: 1em; -} - -.dependency:hover { - box-shadow: dimgrey 0.2em 0.2em 0.2em 0em; -} - -.dependency .index { - font-size: larger; - font-weight: lighter; -} - -.dependency-prop { - padding: 0.3em; -} - -.dependency-prop:hover { - background: rgba(50, 50, 50, 0.25); -} - -.dependency-prop label { - font-weight: bold; -} - -.dependency-value { - padding-left: 1em; -} - -.dependency-value ul { - margin-top: 0; - margin-bottom: 0; -} diff --git a/buildSrc/src/main/resources/license-report.template.html b/buildSrc/src/main/resources/license-report.template.html deleted file mode 100644 index 1a714d2..0000000 --- a/buildSrc/src/main/resources/license-report.template.html +++ /dev/null @@ -1,71 +0,0 @@ - - - Dependency License Report for $name - - - -
- - -
-
-

${project.name} ${!"unspecified".equals(project.version) ? project.version : ""}

-

Dependency License Report

-

- ${new Date().format("yyyy-MM-dd HH:mm:ss z")} -

-
- -

${name}

- - - <% externalInventories.each { name, modules -> %> -

${name}

- - <% } %> -
- - -
-

${name}

- <% inventory.keySet().sort().each { license -> %> - -

${license}

- <% inventory[license].sort({ a, b -> a.group <=> b.group }).each { data -> - printDependency.call(out, data) - } %> - <% } %> - - <% externalInventories.keySet().sort().each { String name -> %> -

${name}

- <% externalInventories[name].each { String license, dependencies -> %> - - <% dependencies.each { importedData -> - printImportedDependency.call(out, importedData) - } %> - <% } %> - <% } %> -
-
- - \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index ccebba7710deaf9f98673a68957ea02138b60d0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61608 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 829e1a5..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip -networkTimeout=10000 -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 79a61d4..0000000 --- a/gradlew +++ /dev/null @@ -1,244 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 93e3f59..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bdaac56 --- /dev/null +++ b/pom.xml @@ -0,0 +1,138 @@ + + 4.0.0 + + org.dflib + jjava + 1.0-M2 + Java Jupyter Kernel + + + UTF-8 + UTF-8 + 11 + + 2.3.0 + 2.5.2 + 3.6.0 + 5.10.1 + + + https://github.com/dflib/jjava + + + scm:git:https://github.com/dflib/jjava + scm:git:ssh://git@github.com/dflib/jjava + https://github.com/dflib/jjava + HEAD + + + + + io.github.spencerpark + jupyter-jvm-basekernel + ${jupyter.jvm.basekernel.version} + + + org.apache.ivy + ivy + ${ivy.version} + + + org.apache.maven + maven-model-builder + ${maven.model.builder.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit5.version} + test + + + + + + + maven-compiler-plugin + 3.13.0 + + + maven-surefire-plugin + 3.2.5 + + + maven-failsafe-plugin + 3.2.5 + + + integration-test + + integration-test + verify + + + + + + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + * + + META-INF/*.MF + META-INF/DEPENDENCIES + + + + false + + + + false + + + + io.github.spencerpark.ijava.IJava + + + + + + + maven-resources-plugin + 3.3.1 + + + maven-assembly-plugin + 3.7.1 + + + assemble-zip + install + + single + + + + assembly/zip/zip.xml + + false + + + + + + + diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d677ac0..0000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'jjava' \ No newline at end of file diff --git a/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java b/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java index 2d36dd6..4858e21 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java +++ b/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java @@ -183,7 +183,8 @@ public Enumeration findResources(String name) throws IOException { private URL doFindResource(String name) { if (classFiles.containsKey(name)) { try { - return URL.of(new URI("jshell", null, "/" + name, null), + return new URL(null, + new URI("jshell", null, "/" + name, null).toString(), new RemoteClassLoader.ResourceURLStreamHandler(name)); } catch (MalformedURLException | URISyntaxException ex) { throw new InternalError(ex); From feab59e80b237bf6be80c7f1eb21112808579c24 Mon Sep 17 00:00:00 2001 From: Nikita Timofeev Date: Sat, 18 May 2024 10:30:27 +0300 Subject: [PATCH 2/8] Switch project to Maven #5 - set version to SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bdaac56..e0e578d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.dflib jjava - 1.0-M2 + 1.0-SNAPSHOT Java Jupyter Kernel From edc2e574f9afe6bc23498751ce21eff666fc91c7 Mon Sep 17 00:00:00 2001 From: Nikita Timofeev Date: Sat, 18 May 2024 10:32:08 +0300 Subject: [PATCH 3/8] Switch project to Maven #5 - release notes --- RELEASE-NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 40a70cf..16a3f93 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,7 @@ +# 1.0-M2 + +- #5 Switch project to Maven + # 1.0-M1 - #1 Upgrade to Gradle 8.5 From ef9ac2ffb9319bd1364899383d3449675818fcc5 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Fri, 17 May 2024 20:00:35 +0300 Subject: [PATCH 4/8] Rename project --- README.md | 12 +++---- assembly/zip/install.py | 22 ++++++------ docs/display.md | 8 ++--- docs/kernel.md | 6 ++-- docs/magics.md | 4 +-- pom.xml | 2 +- .../IJava.java => org/dflib/jjava/JJava.java} | 22 ++++++------ .../ijava => org/dflib/jjava}/JavaKernel.java | 36 +++++++++++-------- .../dflib/jjava}/execution/CodeEvaluator.java | 20 +++++------ .../execution/CodeEvaluatorBuilder.java | 8 ++--- .../execution/CompilationException.java | 2 +- .../EvaluationInterruptedException.java | 2 +- .../execution/EvaluationTimeoutException.java | 2 +- .../execution/IncompleteSourceException.java | 2 +- .../execution/JJavaExecutionControl.java} | 16 ++++----- .../JJavaExecutionControlProvider.java} | 16 ++++----- .../jjava/execution/JJavaLoaderDelegate.java} | 6 ++-- .../execution/LazyInputStreamDelegate.java | 2 +- .../execution/LazyOutputStreamDelegate.java | 2 +- .../execution/MagicsSourceTransformer.java | 2 +- .../dflib/jjava}/magics/ClasspathMagics.java | 2 +- .../dflib/jjava}/magics/MavenResolver.java | 18 +++++----- .../dependencies/CommonRepositories.java | 2 +- .../jjava}/magics/dependencies/Maven.java | 2 +- .../magics/dependencies/MavenToIvy.java | 6 ++-- .../dflib/jjava}/runtime/Display.java | 16 ++++----- .../dflib/jjava}/runtime/Kernel.java | 10 +++--- .../dflib/jjava}/runtime/Magics.java | 14 ++++---- ...l-init.jshell => jjava-jshell-init.jshell} | 6 ++-- ...tadata.json => jjava-kernel-metadata.json} | 0 30 files changed, 137 insertions(+), 131 deletions(-) rename src/main/java/{io/github/spencerpark/ijava/IJava.java => org/dflib/jjava/JJava.java} (86%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/JavaKernel.java (92%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/CodeEvaluator.java (94%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/CodeEvaluatorBuilder.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/CompilationException.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/EvaluationInterruptedException.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/EvaluationTimeoutException.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/IncompleteSourceException.java (96%) rename src/main/java/{io/github/spencerpark/ijava/execution/IJavaExecutionControl.java => org/dflib/jjava/execution/JJavaExecutionControl.java} (94%) rename src/main/java/{io/github/spencerpark/ijava/execution/IJavaExecutionControlProvider.java => org/dflib/jjava/execution/JJavaExecutionControlProvider.java} (88%) rename src/main/java/{io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java => org/dflib/jjava/execution/JJavaLoaderDelegate.java} (98%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/LazyInputStreamDelegate.java (98%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/LazyOutputStreamDelegate.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/execution/MagicsSourceTransformer.java (98%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/magics/ClasspathMagics.java (98%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/magics/MavenResolver.java (97%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/magics/dependencies/CommonRepositories.java (98%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/magics/dependencies/Maven.java (99%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/magics/dependencies/MavenToIvy.java (89%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/runtime/Display.java (87%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/runtime/Kernel.java (85%) rename src/main/java/{io/github/spencerpark/ijava => org/dflib/jjava}/runtime/Magics.java (85%) rename src/main/resources/{ijava-jshell-init.jshell => jjava-jshell-init.jshell} (58%) rename src/main/resources/{ijava-kernel-metadata.json => jjava-kernel-metadata.json} (100%) diff --git a/README.md b/README.md index adf557d..6c8a5c7 100644 --- a/README.md +++ b/README.md @@ -139,11 +139,11 @@ Configuring the kernel can be done via environment variables. These can be set o | Environment variable | Parameter name | Default | Description | |----------------------|----------------|---------|-------------| -| `IJAVA_COMPILER_OPTS` | `comp-opts` | `""` | A space delimited list of command line options that would be passed to the `javac` command when compiling a project. For example `-parameters` to enable retaining parameter names for reflection. | -| `IJAVA_TIMEOUT` | `timeout` | `"-1"` | A duration specifying a timeout (in milliseconds by default) for a _single top level statement_. If less than `1` then there is no timeout. If desired a time may be specified with a [`TimeUnit`](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/TimeUnit.html) may be given following the duration number (ex `"30 SECONDS"`). | -| `IJAVA_CLASSPATH` | `classpath` | `""` | A file path separator delimited list of classpath entries that should be available to the user code. **Important:** no matter what OS, this should use forward slash "/" as the file separator. Also each path may actually be a [simple glob](#simple-glob-syntax). | -| `IJAVA_STARTUP_SCRIPTS_PATH` | `startup-scripts-path` | `""` | A file path seperator delimited list of `.jshell` scripts to run on startup. This includes [ijava-jshell-init.jshell](src/main/resources/ijava-jshell-init.jshell) and [ijava-display-init.jshell](src/main/resources/ijava-display-init.jshell). **Important:** no matter what OS, this should use forward slash "/" as the file separator. Also each path may actually be a [simple glob](#simple-glob-syntax). | -| `IJAVA_STARTUP_SCRIPT` | `startup-script` | `""` | A block of java code to run when the kernel starts up. This may be something like `import my.utils;` to setup some default imports or even `void sleep(long time) { try {Thread.sleep(time); } catch (InterruptedException e) { throw new RuntimeException(e); }}` to declare a default utility method to use in the notebook. | +| `JJAVA_COMPILER_OPTS` | `comp-opts` | `""` | A space delimited list of command line options that would be passed to the `javac` command when compiling a project. For example `-parameters` to enable retaining parameter names for reflection. | +| `JJAVA_TIMEOUT` | `timeout` | `"-1"` | A duration specifying a timeout (in milliseconds by default) for a _single top level statement_. If less than `1` then there is no timeout. If desired a time may be specified with a [`TimeUnit`](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/TimeUnit.html) may be given following the duration number (ex `"30 SECONDS"`). | +| `JJAVA_CLASSPATH` | `classpath` | `""` | A file path separator delimited list of classpath entries that should be available to the user code. **Important:** no matter what OS, this should use forward slash "/" as the file separator. Also each path may actually be a [simple glob](#simple-glob-syntax). | +| `JJAVA_STARTUP_SCRIPTS_PATH` | `startup-scripts-path` | `""` | A file path seperator delimited list of `.jshell` scripts to run on startup. This includes [jjava-jshell-init.jshell](src/main/resources/jjava-jshell-init.jshell) and [jjava-display-init.jshell](src/main/resources/jjava-display-init.jshell). **Important:** no matter what OS, this should use forward slash "/" as the file separator. Also each path may actually be a [simple glob](#simple-glob-syntax). | +| `JJAVA_STARTUP_SCRIPT` | `startup-script` | `""` | A block of java code to run when the kernel starts up. This may be something like `import my.utils;` to setup some default imports or even `void sleep(long time) { try {Thread.sleep(time); } catch (InterruptedException e) { throw new RuntimeException(e); }}` to declare a default utility method to use in the notebook. | ##### Simple glob syntax @@ -161,7 +161,7 @@ Any relative paths are resolved from the notebook server's working directory. Fo See the [List of options](#list-of-options) section for all of the configuration options. -To change compiler options use the `IJAVA_COMPILER_OPTS` environment variable (or `--comp-opts` parameter during installation) with a string of flags as if running the `javac` command. +To change compiler options use the `JJAVA_COMPILER_OPTS` environment variable (or `--comp-opts` parameter during installation) with a string of flags as if running the `javac` command. The kernel VM parameters must currently be assigned in the `kernel.json` by adding/editing a JSON dictionary at the `env` key and changing the `argv` list. To find where the kernel is installed run diff --git a/assembly/zip/install.py b/assembly/zip/install.py index 78bca62..16d9be0 100644 --- a/assembly/zip/install.py +++ b/assembly/zip/install.py @@ -6,26 +6,26 @@ from jupyter_client.kernelspec import KernelSpecManager ALIASES = { - "IJAVA_CLASSPATH": { + "JJAVA_CLASSPATH": { }, - "IJAVA_COMPILER_OPTS": { + "JJAVA_COMPILER_OPTS": { }, - "IJAVA_STARTUP_SCRIPTS_PATH": { + "JJAVA_STARTUP_SCRIPTS_PATH": { }, - "IJAVA_STARTUP_SCRIPT": { + "JJAVA_STARTUP_SCRIPT": { }, - "IJAVA_TIMEOUT": { + "JJAVA_TIMEOUT": { "NO_TIMEOUT": "-1", }, } NAME_MAP = { - "classpath": "IJAVA_CLASSPATH", - "comp-opts": "IJAVA_COMPILER_OPTS", - "startup-scripts-path": "IJAVA_STARTUP_SCRIPTS_PATH", - "startup-script": "IJAVA_STARTUP_SCRIPT", - "timeout": "IJAVA_TIMEOUT", + "classpath": "JJAVA_CLASSPATH", + "comp-opts": "JJAVA_COMPILER_OPTS", + "startup-scripts-path": "JJAVA_STARTUP_SCRIPTS_PATH", + "startup-script": "JJAVA_STARTUP_SCRIPT", + "timeout": "JJAVA_TIMEOUT", } @@ -130,7 +130,7 @@ def __call__(self, parser, namespace, value, option_string=None): action=EnvVar, aliases=ALIASES, name_map=NAME_MAP, - help="A file path seperator delimited list of `.jshell` scripts to run on startup. This includes ijava-jshell-init.jshell and ijava-display-init.jshell. **Important:** no matter what OS, this should use forward slash \"/\" as the file separator. Also each path may actually be a simple glob.", + help="A file path separator delimited list of `.jshell` scripts to run on startup. This includes jjava-jshell-init.jshell and jjava-display-init.jshell. **Important:** no matter what OS, this should use forward slash \"/\" as the file separator. Also each path may actually be a simple glob.", type=type_assertion("startup-scripts-path", str), list_sep=os.pathsep, ) diff --git a/docs/display.md b/docs/display.md index c21794c..695071a 100644 --- a/docs/display.md +++ b/docs/display.md @@ -1,10 +1,10 @@ # Display -One of the many great things about the Jupyter front ends is the support for [`display_data`](http://jupyter-client.readthedocs.io/en/stable/messaging.html#display-data). IJava interfaces with the [base kernel](https://github.com/SpencerPark/jupyter-jvm-basekernel)'s high level rendering API. +One of the many great things about the Jupyter front ends is the support for [`display_data`](http://jupyter-client.readthedocs.io/en/stable/messaging.html#display-data). JJava interfaces with the [base kernel](https://github.com/SpencerPark/jupyter-jvm-basekernel)'s high level rendering API. ## Notebook functions -IJava injects 2 functions into the user space for displaying data: `display` and `render`. Most use cases should prefer the former but there is a necessary case for `render` that is outline below. In addition the `updateDisplay` function can be used to update a previously displayed object. All are defined in the runtime [Display](/src/main/java/io/github/spencerpark/ijava/runtime/Display.java) class. +JJava injects 2 functions into the user space for displaying data: `display` and `render`. Most use cases should prefer the former but there is a necessary case for `render` that is outline below. In addition the `updateDisplay` function can be used to update a previously displayed object. All are defined in the runtime [Display](/src/main/java/org/dflib/jjava/runtime/Display.java) class. All display/render functions include a `text/plain` representation in their output. By default this is the `String.valueOf(Object)` value but it can be overridden. @@ -23,7 +23,7 @@ The object is rendered and published on the display stream. An id is returned wh This is useful when a type has many potential representations but not all are preferred. For example a `CharSequence` has many representations but only the `text/plain` is preferred. To display it as executable javascript we can use the following: ```java -display("alert('Hello from IJava!');", "application/javascript"); +display("alert('Hello from JJava!');", "application/javascript"); ``` Since there is the potential that some front ends don't support a given format many can be given and the front end chooses the best. For example, to display as html and markdown: @@ -46,7 +46,7 @@ Renders an object as the **requested** types and returns it's rendered format. S When expressions are the last code unit in a cell they are rendered with the `render(Object o)` semantics. If this is not desired it can be hijacked by wrapping it in a call to this function. ```java -String md = "Hello from **IJava**"; +String md = "Hello from **JJava**"; render(md, "text/markdown") ``` diff --git a/docs/kernel.md b/docs/kernel.md index ac9c161..e952326 100644 --- a/docs/kernel.md +++ b/docs/kernel.md @@ -1,14 +1,14 @@ # Kernel -All code running in IJava flows through the kernel. This makes it the place to register magics, add things to the classpath, and perform many jupyter related operations. +All code running in JJava flows through the kernel. This makes it the place to register magics, add things to the classpath, and perform many jupyter related operations. ## Notebook functions -IJava injects a function for getting the active kernel instance and additional helpers for making use of the kernel at runtime. These are defined in the runtime [Kernel](/src/main/java/io/github/spencerpark/ijava/runtime/Kernel.java) class. +JJava injects a function for getting the active kernel instance and additional helpers for making use of the kernel at runtime. These are defined in the runtime [Kernel](/src/main/java/org/dflib/jjava/runtime/Kernel.java) class. ### `JavaKernel getKernelInstance()` -Get a reference to the current kernel. It may return null if called outside of a kernel context but should be considered `@NonNull` when inside a notebook or similar. The kernel api has lots of goodies, look at the [JavaKernel](/src/main/java/io/github/spencerpark/ijava/runtime/Kernel.java) class for more information. Specifically there is access to adding to the classpath, getting the magics registry and maven resolver, and access to eval. +Get a reference to the current kernel. It may return null if called outside of a kernel context but should be considered `@NonNull` when inside a notebook or similar. The kernel api has lots of goodies, look at the [JavaKernel](/src/main/java/org/dflib/jjava/runtime/Kernel.java) class for more information. Specifically there is access to adding to the classpath, getting the magics registry and maven resolver, and access to eval. ### `Object eval(String expr) throws Exception` diff --git a/docs/magics.md b/docs/magics.md index f6bf8ea..c6f645b 100644 --- a/docs/magics.md +++ b/docs/magics.md @@ -1,6 +1,6 @@ # Magics -Magics in IJava are very similar to those from IPython. There are: +Magics in JJava are very similar to those from IPython. There are: * **Line magics**: which are inline function calls via a magic function. @@ -31,7 +31,7 @@ The magics simply desugar to calls to `lineMagic` and `cellMagic` in case progra * ` T lineMagic(String name, java.util.List args)` * ` T cellMagic(String name, java.util.List args, String body)` -## Magics provided by IJava +## Magics provided by JJava Things that are likely to become magics are kernel meta functions or functions that operate on source code. Magics should only be used for things that only appear in a Jupyter-like context and only use string arguments. Other things (like `display` and `render`) should be provided as plain functions. diff --git a/pom.xml b/pom.xml index e0e578d..65ca9f6 100644 --- a/pom.xml +++ b/pom.xml @@ -104,7 +104,7 @@ - io.github.spencerpark.ijava.IJava + org.dflib.jjava.JJava diff --git a/src/main/java/io/github/spencerpark/ijava/IJava.java b/src/main/java/org/dflib/jjava/JJava.java similarity index 86% rename from src/main/java/io/github/spencerpark/ijava/IJava.java rename to src/main/java/org/dflib/jjava/JJava.java index 05dcc91..1b98934 100644 --- a/src/main/java/io/github/spencerpark/ijava/IJava.java +++ b/src/main/java/org/dflib/jjava/JJava.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava; +package org.dflib.jjava; import com.google.gson.JsonElement; import com.google.gson.JsonParser; @@ -38,23 +38,23 @@ import java.nio.file.Paths; import java.util.logging.Level; -public class IJava { - public static final String COMPILER_OPTS_KEY = "IJAVA_COMPILER_OPTS"; - public static final String TIMEOUT_DURATION_KEY = "IJAVA_TIMEOUT"; - public static final String CLASSPATH_KEY = "IJAVA_CLASSPATH"; - public static final String STARTUP_SCRIPTS_KEY = "IJAVA_STARTUP_SCRIPTS_PATH"; - public static final String STARTUP_SCRIPT_KEY = "IJAVA_STARTUP_SCRIPT"; +public class JJava { + public static final String COMPILER_OPTS_KEY = "JJAVA_COMPILER_OPTS"; + public static final String TIMEOUT_DURATION_KEY = "JJAVA_TIMEOUT"; + public static final String CLASSPATH_KEY = "JJAVA_CLASSPATH"; + public static final String STARTUP_SCRIPTS_KEY = "JJAVA_STARTUP_SCRIPTS_PATH"; + public static final String STARTUP_SCRIPT_KEY = "JJAVA_STARTUP_SCRIPT"; - public static final String DEFAULT_SHELL_INIT_RESOURCE_PATH = "ijava-jshell-init.jshell"; + public static final String DEFAULT_SHELL_INIT_RESOURCE_PATH = "jjava-jshell-init.jshell"; public static final String VERSION; public static InputStream resource(String path) { - return IJava.class.getClassLoader().getResourceAsStream(path); + return JJava.class.getClassLoader().getResourceAsStream(path); } static { - InputStream metaStream = resource("ijava-kernel-metadata.json"); + InputStream metaStream = resource("jjava-kernel-metadata.json"); Reader metaReader = new InputStreamReader(metaStream); try { JsonElement meta = new JsonParser().parse(metaReader); @@ -79,7 +79,7 @@ public static InputStream resource(String path) { * one has not yet (or already created and finished) been created. */ public static JavaKernel getKernelInstance() { - return IJava.kernel; + return JJava.kernel; } public static void main(String[] args) throws Exception { diff --git a/src/main/java/io/github/spencerpark/ijava/JavaKernel.java b/src/main/java/org/dflib/jjava/JavaKernel.java similarity index 92% rename from src/main/java/io/github/spencerpark/ijava/JavaKernel.java rename to src/main/java/org/dflib/jjava/JavaKernel.java index b61d3af..df34bb3 100644 --- a/src/main/java/io/github/spencerpark/ijava/JavaKernel.java +++ b/src/main/java/org/dflib/jjava/JavaKernel.java @@ -21,11 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava; - -import io.github.spencerpark.ijava.execution.*; -import io.github.spencerpark.ijava.magics.ClasspathMagics; -import io.github.spencerpark.ijava.magics.MavenResolver; +package org.dflib.jjava; + +import org.dflib.jjava.execution.CodeEvaluator; +import org.dflib.jjava.execution.CodeEvaluatorBuilder; +import org.dflib.jjava.execution.CompilationException; +import org.dflib.jjava.execution.EvaluationInterruptedException; +import org.dflib.jjava.execution.EvaluationTimeoutException; +import org.dflib.jjava.execution.IncompleteSourceException; +import org.dflib.jjava.execution.MagicsSourceTransformer; +import org.dflib.jjava.magics.ClasspathMagics; +import org.dflib.jjava.magics.MavenResolver; import io.github.spencerpark.jupyter.kernel.BaseKernel; import io.github.spencerpark.jupyter.kernel.LanguageInfo; import io.github.spencerpark.jupyter.kernel.ReplacementOptions; @@ -78,12 +84,12 @@ public static String maybeCompleteCodeSignifier() { public JavaKernel() { this.evaluator = new CodeEvaluatorBuilder() - .addClasspathFromString(System.getenv(IJava.CLASSPATH_KEY)) - .compilerOptsFromString(System.getenv(IJava.COMPILER_OPTS_KEY)) - .startupScript(IJava.resource(IJava.DEFAULT_SHELL_INIT_RESOURCE_PATH)) - .startupScriptFiles(System.getenv(IJava.STARTUP_SCRIPTS_KEY)) - .startupScript(System.getenv(IJava.STARTUP_SCRIPT_KEY)) - .timeoutFromString(System.getenv(IJava.TIMEOUT_DURATION_KEY)) + .addClasspathFromString(System.getenv(JJava.CLASSPATH_KEY)) + .compilerOptsFromString(System.getenv(JJava.COMPILER_OPTS_KEY)) + .startupScript(JJava.resource(JJava.DEFAULT_SHELL_INIT_RESOURCE_PATH)) + .startupScriptFiles(System.getenv(JJava.STARTUP_SCRIPTS_KEY)) + .startupScript(System.getenv(JJava.STARTUP_SCRIPT_KEY)) + .timeoutFromString(System.getenv(JJava.TIMEOUT_DURATION_KEY)) .sysStdout() .sysStderr() .sysStdin() @@ -94,7 +100,7 @@ public JavaKernel() { this.magics = new Magics(); this.magics.registerMagics(this.mavenResolver); this.magics.registerMagics(new ClasspathMagics(this::addToClasspath)); - this.magics.registerMagics(new Load(List.of(".jsh", ".jshell", ".java", ".ijava"), this::eval)); + this.magics.registerMagics(new Load(List.of(".jsh", ".jshell", ".java", ".jjava"), this::eval)); this.languageInfo = new LanguageInfo.Builder("Java") .version(Runtime.version().toString()) @@ -103,16 +109,16 @@ public JavaKernel() { .pygments("java") .codemirror("java") .build(); - this.banner = String.format("Java %s :: IJava kernel %s \nProtocol v%s implementation by %s %s", + this.banner = String.format("Java %s :: JJava kernel %s \nProtocol v%s implementation by %s %s", Runtime.version().toString(), - IJava.VERSION, + JJava.VERSION, Header.PROTOCOL_VERISON, KERNEL_META.getOrDefault("project", "UNKNOWN"), KERNEL_META.getOrDefault("version", "UNKNOWN") ); this.helpLinks = List.of( new LanguageInfo.Help("Java tutorial", "https://docs.oracle.com/javase/tutorial/java/nutsandbolts/index.html"), - new LanguageInfo.Help("IJava homepage", "https://github.com/SpencerPark/IJava") + new LanguageInfo.Help("JJava homepage", "https://github.com/dflib/jjava") ); this.errorStyler = new StringStyler.Builder() diff --git a/src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluator.java b/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java similarity index 94% rename from src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluator.java rename to src/main/java/org/dflib/jjava/execution/CodeEvaluator.java index 0cdba5d..d00e332 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluator.java +++ b/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; -import io.github.spencerpark.ijava.JavaKernel; +import org.dflib.jjava.JavaKernel; import jdk.jshell.*; import java.lang.reflect.Method; @@ -48,7 +48,7 @@ public class CodeEvaluator { } private final JShell shell; - private final IJavaExecutionControlProvider executionControlProvider; + private final JJavaExecutionControlProvider executionControlProvider; private final String executionControlID; private final SourceCodeAnalysis sourceAnalyzer; @@ -57,7 +57,7 @@ public class CodeEvaluator { private final String indentation = " "; - public CodeEvaluator(JShell shell, IJavaExecutionControlProvider executionControlProvider, String executionControlID, List startupScripts) { + public CodeEvaluator(JShell shell, JJavaExecutionControlProvider executionControlProvider, String executionControlID, List startupScripts) { this.shell = shell; this.executionControlProvider = executionControlProvider; this.executionControlID = executionControlID; @@ -81,7 +81,7 @@ private void init() throws Exception { } protected Object evalSingle(String code) throws Exception { - IJavaExecutionControl executionControl = + JJavaExecutionControl executionControl = this.executionControlProvider.getRegisteredControlByID(this.executionControlID); List events = this.shell.eval(code); @@ -103,7 +103,7 @@ protected Object evalSingle(String code) throws Exception { Snippet.SubKind subKind = event.snippet().subKind(); // Only executable snippets make their way through the machinery we have setup in the - // IJavaExecutionControl. Declarations for example simply take their default value without + // JJavaExecutionControl. Declarations for example simply take their default value without // being executed. Object value = subKind.isExecutable() ? executionControl.takeResult(key) @@ -128,9 +128,9 @@ protected Object evalSingle(String code) throws Exception { if (e != null) { if (e instanceof EvalException) { switch (((EvalException) e).getExceptionClassName()) { - case IJavaExecutionControl.EXECUTION_TIMEOUT_NAME: + case JJavaExecutionControl.EXECUTION_TIMEOUT_NAME: throw new EvaluationTimeoutException(executionControl.getTimeoutDuration(), executionControl.getTimeoutUnit(), code.trim()); - case IJavaExecutionControl.EXECUTION_INTERRUPTED_NAME: + case JJavaExecutionControl.EXECUTION_INTERRUPTED_NAME: throw new EvaluationInterruptedException(code.trim()); default: throw e; @@ -174,7 +174,7 @@ public Object eval(String code) throws Exception { */ private void dropSnippet(Snippet snippet) throws Exception { - IJavaExecutionControl executionControl = + JJavaExecutionControl executionControl = this.executionControlProvider.getRegisteredControlByID(this.executionControlID); this.shell.drop(snippet); // snippet.classFullName() returns name of a wrapper class created for a snippet @@ -251,7 +251,7 @@ public String isComplete(String code) { } public void interrupt() { - IJavaExecutionControl executionControl = + JJavaExecutionControl executionControl = this.executionControlProvider.getRegisteredControlByID(this.executionControlID); if (executionControl != null) diff --git a/src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluatorBuilder.java b/src/main/java/org/dflib/jjava/execution/CodeEvaluatorBuilder.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluatorBuilder.java rename to src/main/java/org/dflib/jjava/execution/CodeEvaluatorBuilder.java index 0ff23e7..f7a845b 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/CodeEvaluatorBuilder.java +++ b/src/main/java/org/dflib/jjava/execution/CodeEvaluatorBuilder.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import io.github.spencerpark.jupyter.kernel.util.GlobFinder; import jdk.jshell.JShell; @@ -183,14 +183,14 @@ public CodeEvaluatorBuilder startupScriptFile(Path path) { } public CodeEvaluator build() { - IJavaExecutionControlProvider executionControlProvider = new IJavaExecutionControlProvider(); + JJavaExecutionControlProvider executionControlProvider = new JJavaExecutionControlProvider(); String executionControlID = UUID.randomUUID().toString(); Map executionControlParams = new LinkedHashMap<>(); - executionControlParams.put(IJavaExecutionControlProvider.REGISTRATION_ID_KEY, executionControlID); + executionControlParams.put(JJavaExecutionControlProvider.REGISTRATION_ID_KEY, executionControlID); if (this.timeout != null) - executionControlParams.put(IJavaExecutionControlProvider.TIMEOUT_KEY, this.timeout); + executionControlParams.put(JJavaExecutionControlProvider.TIMEOUT_KEY, this.timeout); JShell.Builder builder = JShell.builder(); if (this.out != null) builder.out(this.out); diff --git a/src/main/java/io/github/spencerpark/ijava/execution/CompilationException.java b/src/main/java/org/dflib/jjava/execution/CompilationException.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/execution/CompilationException.java rename to src/main/java/org/dflib/jjava/execution/CompilationException.java index 33777f4..fee801e 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/CompilationException.java +++ b/src/main/java/org/dflib/jjava/execution/CompilationException.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import jdk.jshell.SnippetEvent; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/EvaluationInterruptedException.java b/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/execution/EvaluationInterruptedException.java rename to src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java index 26d0b0c..ffcb6a5 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/EvaluationInterruptedException.java +++ b/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; public class EvaluationInterruptedException extends Exception { private final String source; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/EvaluationTimeoutException.java b/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/execution/EvaluationTimeoutException.java rename to src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java index 9765e31..c6622a8 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/EvaluationTimeoutException.java +++ b/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/IncompleteSourceException.java b/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java similarity index 96% rename from src/main/java/io/github/spencerpark/ijava/execution/IncompleteSourceException.java rename to src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java index 263b7b0..36895d7 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/IncompleteSourceException.java +++ b/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; public class IncompleteSourceException extends Exception { private final String source; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControl.java b/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java similarity index 94% rename from src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControl.java rename to src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java index 6359afe..aa16296 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControl.java +++ b/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import jdk.jshell.EvalException; import jdk.jshell.execution.DirectExecutionControl; @@ -39,7 +39,7 @@ * An ExecutionControl very similar to {@link jdk.jshell.execution.LocalExecutionControl} but which * also logs the actual result of an invocation before being serialized. */ -public class IJavaExecutionControl extends DirectExecutionControl { +public class JJavaExecutionControl extends DirectExecutionControl { /** * A special "class name" for a {@link jdk.jshell.spi.ExecutionControl.UserException} such that it may be * identified after serialization into an {@link jdk.jshell.EvalException} via {@link @@ -66,18 +66,18 @@ public class IJavaExecutionControl extends DirectExecutionControl { private final ConcurrentMap> running = new ConcurrentHashMap<>(); private final Map results = new ConcurrentHashMap<>(); - private final IJavaLoaderDelegate loaderDelegate; + private final JJavaLoaderDelegate loaderDelegate; - public IJavaExecutionControl() { + public JJavaExecutionControl() { this(-1, TimeUnit.MILLISECONDS); } - public IJavaExecutionControl(long timeoutTime, TimeUnit timeoutUnit) { + public JJavaExecutionControl(long timeoutTime, TimeUnit timeoutUnit) { super(null); - this.loaderDelegate = new IJavaLoaderDelegate(); + this.loaderDelegate = new JJavaLoaderDelegate(); this.timeoutTime = timeoutTime; this.timeoutUnit = timeoutTime > 0 ? Objects.requireNonNull(timeoutUnit) : TimeUnit.MILLISECONDS; - this.executor = Executors.newCachedThreadPool(r -> new Thread(r, "IJava-executor-" + EXECUTOR_THREAD_ID.getAndIncrement())); + this.executor = Executors.newCachedThreadPool(r -> new Thread(r, "JJava-executor-" + EXECUTOR_THREAD_ID.getAndIncrement())); } public long getTimeoutDuration() { @@ -197,7 +197,7 @@ void unloadClass(String className) throws ClassNotFoundException { @Override public String toString() { - return "IJavaExecutionControl{" + + return "JJavaExecutionControl{" + "timeoutTime=" + timeoutTime + ", timeoutUnit=" + timeoutUnit + '}'; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControlProvider.java b/src/main/java/org/dflib/jjava/execution/JJavaExecutionControlProvider.java similarity index 88% rename from src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControlProvider.java rename to src/main/java/org/dflib/jjava/execution/JJavaExecutionControlProvider.java index ac12319..4e23d95 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/IJavaExecutionControlProvider.java +++ b/src/main/java/org/dflib/jjava/execution/JJavaExecutionControlProvider.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControlProvider; @@ -33,7 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class IJavaExecutionControlProvider implements ExecutionControlProvider { +public class JJavaExecutionControlProvider implements ExecutionControlProvider { /** * The parameter key that when given causes the generated control to be registered * for later reference by the parameter value. @@ -49,15 +49,15 @@ public class IJavaExecutionControlProvider implements ExecutionControlProvider { private static final Pattern TIMEOUT_PATTERN = Pattern.compile("^(?-?\\d+)\\W*(?[A-Za-z]+)?$"); - private final Map controllers = new WeakHashMap<>(); + private final Map controllers = new WeakHashMap<>(); - public IJavaExecutionControl getRegisteredControlByID(String id) { + public JJavaExecutionControl getRegisteredControlByID(String id) { return this.controllers.get(id); } @Override public String name() { - return "IJava"; + return "JJava"; } @Override @@ -82,9 +82,9 @@ public ExecutionControl generate(ExecutionEnv env, Map parameter } } - IJavaExecutionControl control = timeout > 0 - ? new IJavaExecutionControl(timeout, timeUnit) - : new IJavaExecutionControl(); + JJavaExecutionControl control = timeout > 0 + ? new JJavaExecutionControl(timeout, timeUnit) + : new JJavaExecutionControl(); String id = parameters.get(REGISTRATION_ID_KEY); if (id != null) diff --git a/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java b/src/main/java/org/dflib/jjava/execution/JJavaLoaderDelegate.java similarity index 98% rename from src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java rename to src/main/java/org/dflib/jjava/execution/JJavaLoaderDelegate.java index 4858e21..c8e1574 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/IJavaLoaderDelegate.java +++ b/src/main/java/org/dflib/jjava/execution/JJavaLoaderDelegate.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import jdk.jshell.execution.LoaderDelegate; import jdk.jshell.spi.ExecutionControl; @@ -54,7 +54,7 @@ /** * This code is a copy of jdk.jshell.execution.DefaultLoaderDelegate, with an option to unload stored classes */ -public class IJavaLoaderDelegate implements LoaderDelegate { +public class JJavaLoaderDelegate implements LoaderDelegate { private final RemoteClassLoader loader; private final Map> klasses = new HashMap<>(); @@ -215,7 +215,7 @@ private static class ClassFile { } } - public IJavaLoaderDelegate() { + public JJavaLoaderDelegate() { this.loader = new RemoteClassLoader(); Thread.currentThread().setContextClassLoader(loader); } diff --git a/src/main/java/io/github/spencerpark/ijava/execution/LazyInputStreamDelegate.java b/src/main/java/org/dflib/jjava/execution/LazyInputStreamDelegate.java similarity index 98% rename from src/main/java/io/github/spencerpark/ijava/execution/LazyInputStreamDelegate.java rename to src/main/java/org/dflib/jjava/execution/LazyInputStreamDelegate.java index 8f270e2..4345831 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/LazyInputStreamDelegate.java +++ b/src/main/java/org/dflib/jjava/execution/LazyInputStreamDelegate.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/LazyOutputStreamDelegate.java b/src/main/java/org/dflib/jjava/execution/LazyOutputStreamDelegate.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/execution/LazyOutputStreamDelegate.java rename to src/main/java/org/dflib/jjava/execution/LazyOutputStreamDelegate.java index 535540c..467ff47 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/LazyOutputStreamDelegate.java +++ b/src/main/java/org/dflib/jjava/execution/LazyOutputStreamDelegate.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/io/github/spencerpark/ijava/execution/MagicsSourceTransformer.java b/src/main/java/org/dflib/jjava/execution/MagicsSourceTransformer.java similarity index 98% rename from src/main/java/io/github/spencerpark/ijava/execution/MagicsSourceTransformer.java rename to src/main/java/org/dflib/jjava/execution/MagicsSourceTransformer.java index 5694641..755e6cd 100644 --- a/src/main/java/io/github/spencerpark/ijava/execution/MagicsSourceTransformer.java +++ b/src/main/java/org/dflib/jjava/execution/MagicsSourceTransformer.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.execution; +package org.dflib.jjava.execution; import io.github.spencerpark.jupyter.kernel.magic.CellMagicParseContext; import io.github.spencerpark.jupyter.kernel.magic.LineMagicParseContext; diff --git a/src/main/java/io/github/spencerpark/ijava/magics/ClasspathMagics.java b/src/main/java/org/dflib/jjava/magics/ClasspathMagics.java similarity index 98% rename from src/main/java/io/github/spencerpark/ijava/magics/ClasspathMagics.java rename to src/main/java/org/dflib/jjava/magics/ClasspathMagics.java index 5b8abd7..8e4df6c 100644 --- a/src/main/java/io/github/spencerpark/ijava/magics/ClasspathMagics.java +++ b/src/main/java/org/dflib/jjava/magics/ClasspathMagics.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.magics; +package org.dflib.jjava.magics; import io.github.spencerpark.jupyter.kernel.magic.registry.LineMagic; import io.github.spencerpark.jupyter.kernel.util.GlobFinder; diff --git a/src/main/java/io/github/spencerpark/ijava/magics/MavenResolver.java b/src/main/java/org/dflib/jjava/magics/MavenResolver.java similarity index 97% rename from src/main/java/io/github/spencerpark/ijava/magics/MavenResolver.java rename to src/main/java/org/dflib/jjava/magics/MavenResolver.java index b0014bc..1ba4111 100644 --- a/src/main/java/io/github/spencerpark/ijava/magics/MavenResolver.java +++ b/src/main/java/org/dflib/jjava/magics/MavenResolver.java @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.magics; +package org.dflib.jjava.magics; -import io.github.spencerpark.ijava.magics.dependencies.CommonRepositories; -import io.github.spencerpark.ijava.magics.dependencies.Maven; -import io.github.spencerpark.ijava.magics.dependencies.MavenToIvy; +import org.dflib.jjava.magics.dependencies.CommonRepositories; +import org.dflib.jjava.magics.dependencies.Maven; +import org.dflib.jjava.magics.dependencies.MavenToIvy; import io.github.spencerpark.jupyter.kernel.magic.registry.CellMagic; import io.github.spencerpark.jupyter.kernel.magic.registry.LineMagic; import io.github.spencerpark.jupyter.kernel.magic.registry.MagicsArgs; @@ -262,7 +262,7 @@ private File convertPomToIvy(Ivy ivy, File pomFile) throws IOException, ParseExc ModuleDescriptor pomModule = parser.parseDescriptor(new IvySettings(), pomFile.toURI().toURL(), false); - File tempIvyFile = File.createTempFile("ijava-ivy-", ".xml").getAbsoluteFile(); + File tempIvyFile = File.createTempFile("jjava-ivy-", ".xml").getAbsoluteFile(); tempIvyFile.deleteOnExit(); parser.toIvyFile(pomUrl.openStream(), new URLResource(pomUrl), tempIvyFile, pomModule); @@ -309,9 +309,9 @@ private String solidifyPartialPOM(String rawIn) throws ParserConfigurationExcept // Wrap in a dummy tag to allow fragments InputStream inStream = new SequenceInputStream(Collections.enumeration(Arrays.asList( - new ByteArrayInputStream("".getBytes(Charset.forName("utf-8"))), + new ByteArrayInputStream("".getBytes(Charset.forName("utf-8"))), new ByteArrayInputStream(rawIn.getBytes(Charset.forName("utf-8"))), - new ByteArrayInputStream("".getBytes(Charset.forName("utf-8"))) + new ByteArrayInputStream("".getBytes(Charset.forName("utf-8"))) ))); Document doc = builder.parse(inStream); @@ -386,7 +386,7 @@ private String solidifyPartialPOM(String rawIn) throws ParserConfigurationExcept if (!setGroupId) { Node groupId = project.appendChild(fixed.createElement("groupId")); - groupId.setTextContent("ijava.notebook"); + groupId.setTextContent("jjava.notebook"); } if (!setArtifactId) { @@ -470,7 +470,7 @@ public void addMavenRepo(List args) { @CellMagic public void loadFromPOM(List args, String body) throws Exception { try { - File tempPomPath = File.createTempFile("ijava-maven-", ".pom").getAbsoluteFile(); + File tempPomPath = File.createTempFile("jjava-maven-", ".pom").getAbsoluteFile(); tempPomPath.deleteOnExit(); String rawPom = this.solidifyPartialPOM(body); diff --git a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/CommonRepositories.java b/src/main/java/org/dflib/jjava/magics/dependencies/CommonRepositories.java similarity index 98% rename from src/main/java/io/github/spencerpark/ijava/magics/dependencies/CommonRepositories.java rename to src/main/java/org/dflib/jjava/magics/dependencies/CommonRepositories.java index d13bb7a..e4cc7ab 100644 --- a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/CommonRepositories.java +++ b/src/main/java/org/dflib/jjava/magics/dependencies/CommonRepositories.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.magics.dependencies; +package org.dflib.jjava.magics.dependencies; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.IBiblioResolver; diff --git a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/Maven.java b/src/main/java/org/dflib/jjava/magics/dependencies/Maven.java similarity index 99% rename from src/main/java/io/github/spencerpark/ijava/magics/dependencies/Maven.java rename to src/main/java/org/dflib/jjava/magics/dependencies/Maven.java index f798737..34a43aa 100644 --- a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/Maven.java +++ b/src/main/java/org/dflib/jjava/magics/dependencies/Maven.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.magics.dependencies; +package org.dflib.jjava.magics.dependencies; import org.apache.maven.building.StringSource; import org.apache.maven.model.building.*; diff --git a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/MavenToIvy.java b/src/main/java/org/dflib/jjava/magics/dependencies/MavenToIvy.java similarity index 89% rename from src/main/java/io/github/spencerpark/ijava/magics/dependencies/MavenToIvy.java rename to src/main/java/org/dflib/jjava/magics/dependencies/MavenToIvy.java index ee82490..78e0aee 100644 --- a/src/main/java/io/github/spencerpark/ijava/magics/dependencies/MavenToIvy.java +++ b/src/main/java/org/dflib/jjava/magics/dependencies/MavenToIvy.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.magics.dependencies; +package org.dflib.jjava.magics.dependencies; import org.apache.ivy.plugins.resolver.ChainResolver; import org.apache.ivy.plugins.resolver.DependencyResolver; @@ -35,11 +35,11 @@ public class MavenToIvy { public static List getRepositoriesFromModel(CharSequence pom) throws ModelBuildingException { - return MavenToIvy.getRepositoriesFromModel(Maven.getInstance().readEffectiveModel(pom).getEffectiveModel()); + return getRepositoriesFromModel(Maven.getInstance().readEffectiveModel(pom).getEffectiveModel()); } public static List getRepositoriesFromModel(File pom) throws ModelBuildingException { - return MavenToIvy.getRepositoriesFromModel(Maven.getInstance().readEffectiveModel(pom).getEffectiveModel()); + return getRepositoriesFromModel(Maven.getInstance().readEffectiveModel(pom).getEffectiveModel()); } public static List getRepositoriesFromModel(Model model) { diff --git a/src/main/java/io/github/spencerpark/ijava/runtime/Display.java b/src/main/java/org/dflib/jjava/runtime/Display.java similarity index 87% rename from src/main/java/io/github/spencerpark/ijava/runtime/Display.java rename to src/main/java/org/dflib/jjava/runtime/Display.java index 1e2fe8b..197f5bb 100644 --- a/src/main/java/io/github/spencerpark/ijava/runtime/Display.java +++ b/src/main/java/org/dflib/jjava/runtime/Display.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.runtime; +package org.dflib.jjava.runtime; -import io.github.spencerpark.ijava.JavaKernel; +import org.dflib.jjava.JavaKernel; import io.github.spencerpark.jupyter.kernel.display.DisplayData; import java.util.UUID; @@ -35,7 +35,7 @@ public static DisplayData render(Object o) { if (kernel != null) { return kernel.getRenderer().render(o); } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } @@ -45,7 +45,7 @@ public static DisplayData render(Object o, String... as) { if (kernel != null) { return kernel.getRenderer().renderAs(o, as); } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } @@ -65,7 +65,7 @@ public static String display(Object o) { return id; } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } @@ -85,7 +85,7 @@ public static String display(Object o, String... as) { return id; } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } @@ -96,7 +96,7 @@ public static void updateDisplay(String id, Object o) { DisplayData data = kernel.getRenderer().render(o); kernel.getIO().display.updateDisplay(id, data); } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } @@ -107,7 +107,7 @@ public static void updateDisplay(String id, Object o, String... as) { DisplayData data = kernel.getRenderer().renderAs(o, as); kernel.getIO().display.updateDisplay(id, data); } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } } diff --git a/src/main/java/io/github/spencerpark/ijava/runtime/Kernel.java b/src/main/java/org/dflib/jjava/runtime/Kernel.java similarity index 85% rename from src/main/java/io/github/spencerpark/ijava/runtime/Kernel.java rename to src/main/java/org/dflib/jjava/runtime/Kernel.java index a6950a5..a95bde9 100644 --- a/src/main/java/io/github/spencerpark/ijava/runtime/Kernel.java +++ b/src/main/java/org/dflib/jjava/runtime/Kernel.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.runtime; +package org.dflib.jjava.runtime; -import io.github.spencerpark.ijava.IJava; -import io.github.spencerpark.ijava.JavaKernel; +import org.dflib.jjava.JJava; +import org.dflib.jjava.JavaKernel; public class Kernel { public static JavaKernel getKernelInstance() { - return IJava.getKernelInstance(); + return JJava.getKernelInstance(); } public static Object eval(String expr) throws Exception { @@ -37,7 +37,7 @@ public static Object eval(String expr) throws Exception { if (kernel != null) { return kernel.evalRaw(expr); } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } } diff --git a/src/main/java/io/github/spencerpark/ijava/runtime/Magics.java b/src/main/java/org/dflib/jjava/runtime/Magics.java similarity index 85% rename from src/main/java/io/github/spencerpark/ijava/runtime/Magics.java rename to src/main/java/org/dflib/jjava/runtime/Magics.java index 91e8114..9dd465e 100644 --- a/src/main/java/io/github/spencerpark/ijava/runtime/Magics.java +++ b/src/main/java/org/dflib/jjava/runtime/Magics.java @@ -21,17 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package io.github.spencerpark.ijava.runtime; +package org.dflib.jjava.runtime; -import io.github.spencerpark.ijava.IJava; -import io.github.spencerpark.ijava.JavaKernel; +import org.dflib.jjava.JJava; +import org.dflib.jjava.JavaKernel; import io.github.spencerpark.jupyter.kernel.magic.registry.UndefinedMagicException; import java.util.List; public class Magics { public static T lineMagic(String name, List args) { - JavaKernel kernel = IJava.getKernelInstance(); + JavaKernel kernel = JJava.getKernelInstance(); if (kernel != null) { try { @@ -42,12 +42,12 @@ public static T lineMagic(String name, List args) { throw new RuntimeException(String.format("Exception occurred while running line magic '%s': %s", name, e.getMessage()), e); } } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } public static T cellMagic(String name, List args, String body) { - JavaKernel kernel = IJava.getKernelInstance(); + JavaKernel kernel = JJava.getKernelInstance(); if (kernel != null) { try { @@ -58,7 +58,7 @@ public static T cellMagic(String name, List args, String body) { throw new RuntimeException(String.format("Exception occurred while running cell magic '%s': %s", name, e.getMessage()), e); } } else { - throw new RuntimeException("No IJava kernel running"); + throw new RuntimeException("No JJava kernel running"); } } } diff --git a/src/main/resources/ijava-jshell-init.jshell b/src/main/resources/jjava-jshell-init.jshell similarity index 58% rename from src/main/resources/ijava-jshell-init.jshell rename to src/main/resources/jjava-jshell-init.jshell index 9e944c1..ad6419a 100644 --- a/src/main/resources/ijava-jshell-init.jshell +++ b/src/main/resources/jjava-jshell-init.jshell @@ -6,9 +6,9 @@ import java.util.concurrent.*; import java.util.prefs.*; import java.util.regex.*; -import static io.github.spencerpark.ijava.runtime.Display.*; -import static io.github.spencerpark.ijava.runtime.Kernel.*; -import static io.github.spencerpark.ijava.runtime.Magics.*; +import static org.dflib.jjava.runtime.Display.*; +import static org.dflib.jjava.runtime.Kernel.*; +import static org.dflib.jjava.runtime.Magics.*; public void printf(String format, Object... args) { System.out.printf(format, args); diff --git a/src/main/resources/ijava-kernel-metadata.json b/src/main/resources/jjava-kernel-metadata.json similarity index 100% rename from src/main/resources/ijava-kernel-metadata.json rename to src/main/resources/jjava-kernel-metadata.json From 06426ce5a446d4affcca6d38561061bfc2b9b0a4 Mon Sep 17 00:00:00 2001 From: Nikita Timofeev Date: Sat, 18 May 2024 10:36:14 +0300 Subject: [PATCH 5/8] Switch project to Maven #5 - update readme --- README.md | 11 +++++------ pom.xml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index adf557d..8f583db 100644 --- a/README.md +++ b/README.md @@ -123,17 +123,16 @@ Get the latest version of the kernel but possibly run into some issues with inst ``` 2. Build the kernel. - - On *nix `./gradlew zipKernel` - - On windows `gradlew zipKernel` + ```bash + mvn package + ``` -3. Install `build/distributions/jjava-$version.zip` custom build as a pre-built binary +3. Install `target/jjava-$version.zip` custom build as a pre-built binary ### Configuring -Configuring the kernel can be done via environment variables. These can be set on the system or inside the `kernel.json`. The configuration can be done at install time, which may be repeated as often as desired. The parameters are listed with `python3 install.py -h` as well as below in the list of options. Configuration done via the installer (or `gradlew installKernel --param ...:...`) should use the names in the _Parameter name_ column. +Configuring the kernel can be done via environment variables. These can be set on the system or inside the `kernel.json`. The configuration can be done at install time, which may be repeated as often as desired. The parameters are listed with `python3 install.py -h` as well as below in the list of options. #### List of options diff --git a/pom.xml b/pom.xml index e0e578d..69e6fa3 100644 --- a/pom.xml +++ b/pom.xml @@ -120,7 +120,7 @@ assemble-zip - install + package single From a46ff239f3ea20303385c514c4616179a74ec77e Mon Sep 17 00:00:00 2001 From: Nikita Timofeev Date: Sat, 18 May 2024 11:03:39 +0300 Subject: [PATCH 6/8] Release notes for #7 and #8 --- RELEASE-NOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 16a3f93..20f459a 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,8 @@ # 1.0-M2 - #5 Switch project to Maven +- #7 Project renaming +- #8 Java package change # 1.0-M1 From 58b743cac40251102cd186f99ade09b1d8c11088 Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Fri, 17 May 2024 21:20:56 +0300 Subject: [PATCH 7/8] Set up test workflow --- .github/workflows/maven.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..058aaed --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,29 @@ +name: 'build test' + +on: + push: + branches: [ main ] + pull_request: + branches: [ '*' ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + java: [ 11, 17, 21 ] + + steps: + - name: Checkout... + uses: actions/checkout@v4 + + - name: Set up JDK... + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: 'maven' + + - name: Build and test... + run: mvn clean verify -U From f04549a0ab713f8f7e34e90db965a72155afdcfa Mon Sep 17 00:00:00 2001 From: Mikhail Dzianishchyts Date: Sat, 18 May 2024 11:44:11 +0300 Subject: [PATCH 8/8] Set up release workflow --- .github/workflows/release.yml | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..badc168 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,66 @@ +name: 'create release' + +on: + push: + tags: + - '[0-9]+.[0-9]+*' + +jobs: + prepare-release: + runs-on: ubuntu-latest + + outputs: + tag: ${{ steps.vars.outputs.tag }} + version: ${{ steps.vars.outputs.version }} + upload_url: ${{ steps.create_release.outputs.upload_url }} + + steps: + - name: Checkout... + uses: actions/checkout@v4 + + - name: Set version... + id: vars + run: | + RELEASE_TAG=${GITHUB_REF#refs/*/} + echo ::set-output name=tag::${RELEASE_TAG} + echo ::set-output name=version::${RELEASE_TAG:1} + + - name: Create release... + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.vars.outputs.tag }} + release_name: ${{ steps.vars.outputs.tag }} + body: JJava ${{ steps.vars.outputs.tag }} release + draft: true + prerelease: false + + build-and-upload: + needs: prepare-release + runs-on: ubuntu-latest + + steps: + - name: Checkout... + uses: actions/checkout@v4 + + - name: Set up JDK... + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: 'maven' + + - name: Build and test... + run: mvn clean verify -U + + - name: Upload Archive... + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.prepare-release.outputs.upload_url }} + asset_path: ./target/jjava-${{ needs.prepare-release.outputs.version }}.zip + asset_name: jjava-${{ needs.prepare-release.outputs.version }}.zip + asset_content_type: application/zip