diff --git a/build/settings.gradle b/build/settings.gradle index c0216a4822aedef3214cbab94c77c84d7583be67..fb68b5c3bdccc7a68e1eb442b215d16fa19a8e62 100644 --- a/build/settings.gradle +++ b/build/settings.gradle @@ -1,6 +1,6 @@ includeFlat 'lib-commonbase', 'lib-common', 'api-openbis-java', 'lib-openbis-common', 'lib-authentication', 'lib-dbmigration', 'server-application-server', 'server-original-data-store', 'server-screening', 'core-plugin-openbis', 'app-openbis-installer', 'lib-image-readers', 'test-ui-core', - 'test-api-openbis-javascript', 'server-external-data-store', 'ui-admin', 'lib-microservice-server', + 'test-api-openbis-javascript', 'api-openbis-python3-pybis', 'server-external-data-store', 'ui-admin', 'lib-microservice-server', 'lib-transactional-file-system', 'server-data-store', 'ui-eln-lims', 'api-openbis-javascript', - 'lib-json', 'api-data-store-server-java' \ No newline at end of file + 'lib-json', 'api-data-store-server-java', 'lib-base' \ No newline at end of file diff --git a/lib-base/build.gradle b/lib-base/build.gradle index 06ab38d7124713b026faf555d1b931aacc4f59be..e2b93329052ad47ea754db991489a2c409125dbb 100644 --- a/lib-base/build.gradle +++ b/lib-base/build.gradle @@ -1,12 +1,10 @@ -apply from: './javaproject.gradle' - -group='sis' +apply from: '../build/javaproject.gradle' dependencies { - compile 'apache:commons-io:+', - 'apache:commons-lang3:+', - 'testng:testng:+', - 'rinn:restrictions:+' + api 'apache:commons-io:2.6', + 'apache:commons-lang3:3.11', + 'testng:testng:6.8-CISD', + 'rinn:restrictions:1.0.2' } tasks.withType(Test) { @@ -40,31 +38,7 @@ sourcesJar { archiveName "${project.group}-base-${version}-sources.jar" } -task standaloneTestJar(type: Jar, dependsOn: [classes, testClasses]) { - archiveName "${project.group}-base-${version}-tests.jar" - from files(sourceSets.main.output.classesDir) - from files(sourceSets.main.output.resourcesDir) - from files(sourceSets.test.output.classesDir) - from files("libs") - - from('targets/dist') { - include 'BUILD*INFO' - } - - from {configurations.testRuntime.collect {zipTree(it)}} - - manifest { - attributes 'Main-Class': 'ch.systemsx.cisd.base.AllTests' - } -} - -task javadocZip(type: Jar, dependsOn: javadoc) { - archiveName "${project.group}-base-${version}-javadoc.jar" - baseName "${project.group}-base-javadoc" - from javadoc.destinationDir -} - -task distributionZip(type: Zip, dependsOn: [jar, sourcesJar, javadocZip, standaloneTestJar]) { +task distributionZip(type: Zip, dependsOn: [jar, sourcesJar, javadoc, testJar]) { def ver = project.ext.versionNumber.startsWith('SNAPSHOT') ? "${version}" : "" def myVersion = project.ext.versionNumber.startsWith('SNAPSHOT') ? "${project.ext.versionNumber}-${project.ext.revisionNumber}" : project.ext.versionNumber archiveName "${project.group}-base-${myVersion}.zip" @@ -76,19 +50,19 @@ task distributionZip(type: Zip, dependsOn: [jar, sourcesJar, javadocZip, standal into "${project.group}-base/doc" } - from (jar.archivePath) { + from (jar) { into "${project.group}-base/lib" } - from (sourcesJar.archivePath) { + from (sourcesJar) { into "${project.group}-base/src" } - from (standaloneTestJar.archivePath) { + from (testJar) { into "${project.group}-base/lib" } - from (javadocZip.archivePath) { + from (javadoc) { into "${project.group}-base/doc" } } diff --git a/lib-base/dist/COPYING b/lib-base/dist/COPYING index 0bae4727c89b5e38a5c28bff7ff8550dc945aaf5..12b210b1347ecac5f1843c380313da7f774bbf48 100644 --- a/lib-base/dist/COPYING +++ b/lib-base/dist/COPYING @@ -1,5 +1,5 @@ /* - * Copyright 2009 ETH Zuerich, CISD + * Copyright ETH 2023 Zürich, Scientific IT Services * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib-base/gradle/wrapper/gradle-wrapper.jar b/lib-base/gradle/wrapper/gradle-wrapper.jar index 644e4cb7af78425d9774939370f5d17bac923d34..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 Binary files a/lib-base/gradle/wrapper/gradle-wrapper.jar and b/lib-base/gradle/wrapper/gradle-wrapper.jar differ diff --git a/lib-base/gradle/wrapper/gradle-wrapper.properties b/lib-base/gradle/wrapper/gradle-wrapper.properties index 8fe999037d0985a6a05b7f9e74bd4731cee14b5e..7745c4ec463c7bb1c4ff6a5e58db239890345152 100644 --- a/lib-base/gradle/wrapper/gradle-wrapper.properties +++ b/lib-base/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Aug 17 11:54:01 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/gradle/distribution/7.4/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/gradle/distribution/4.9/gradle-4.9-all.zip diff --git a/lib-base/gradlew b/lib-base/gradlew index 4453ccea33d960069d9137ee65f6b21fc65e7e92..83f2acfdc319a24e8766cca78f32474ad7a22dd6 100755 --- a/lib-base/gradlew +++ b/lib-base/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or 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 UN*X @@ -28,16 +44,16 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -109,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` @@ -155,7 +171,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } diff --git a/lib-base/gradlew.bat b/lib-base/gradlew.bat index e95643d6a2ca62258464e83c72f5156dc941c609..24467a141f791695fc1009c78d913b2c849d1412 100644 --- a/lib-base/gradlew.bat +++ b/lib-base/gradlew.bat @@ -1,3 +1,19 @@ +@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 @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/lib-base/javaproject.gradle b/lib-base/javaproject.gradle deleted file mode 100644 index 9c6496c7cebff946c97af9717ab9197eddf6379f..0000000000000000000000000000000000000000 --- a/lib-base/javaproject.gradle +++ /dev/null @@ -1,314 +0,0 @@ -apply plugin: 'java' -apply plugin: 'project-report' - -evaluationDependsOnChildren() - -configurations { - tests { - extendsFrom testRuntime - } -} - -configurations { - ecj -} - -configurations.all { - resolutionStrategy.cacheDynamicVersionsFor 0, 'hours' - resolutionStrategy.cacheChangingModulesFor 0, 'hours' -} - -task wrapper(type: Wrapper) { - gradleVersion = '3.5' - distributionUrl = "http://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/gradle/distribution/3.5/gradle-3.5-all.zip" -} - -sourceCompatibility='1.8' -targetCompatibility='1.8' - -sourceSets { - main { - java { - srcDirs = ['source/java'] - } - } - test { - java { - srcDirs = ['sourceTest/java'] - } - resources { - srcDirs = ['sourceTest/java'] - } - } - examples { - java { - srcDirs = ['sourceExamples/java'] - } - } -} - -buildDir = 'targets/gradle' - -buildscript { - apply from: './repository.gradle' - - repositories repositoryConfig -} - -repositories repositoryConfig - -def execute(command, arguments) { - new ByteArrayOutputStream().withStream { os -> - print "execute: ${command}" - arguments.collect({print " ${it}"}) - println '' - def result = exec { - executable = command - args = arguments - standardOutput = os - } - return os.toString().split('\n') - } -} - -ext.executeFunction = { - command, arguments -> execute(command, arguments) -} - -def execute_working_dir(command, arguments, working_dir) { - new ByteArrayOutputStream().withStream { os -> - print "execute: ${command}" - arguments.collect({print " ${it}"}) - println '' - def result = exec { - executable = command - args = arguments - standardOutput = os - } - return os.toString().split('\n') - } -} - -def isGitProject() { - return new java.io.File(projectDir, ".git").isDirectory() || new java.io.File(projectDir, "../.git").isDirectory() -} - -def calculateCleanFlag() { - if (isGitProject()) { - def output = execute_working_dir('git', ['status', '--porcelain'], '../' + project.name) - return (output.length == 0 || (output.length ==1 && output[0].length() == 0)) ? 'clean' : 'dirty' - } else { - return 'dirty' - } -} - -def findMaximum(lines, key) { - return lines.findAll({ it.startsWith(key)}).collect({element -> element.split(':')[1].toInteger()}).max() -} - -def calculateBuildInfo() { - if (isGitProject()) { - def gitlogoutput = execute_working_dir('git', ['log', '-1', '--format=%at-%H'], '../' + project.name) - def rev = gitlogoutput[0].split("-") - project.ext.revisionNumber = Integer.parseInt(rev[0]) - def commitHash = rev[1] - def date = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").format(new Date(revisionNumber * 1000L)) - project.ext.revisionInfo = "${commitHash} [${date}]" - def tag = 'git tag -l --points-at HEAD'.execute().text.trim() - if (tag == null || tag.isEmpty()) { - project.ext.versionNumber = 'SNAPSHOT' - } else if (tag.contains('pybis')) { - throw new GradleException("project must contain a readme file") - } else { - project.ext.versionNumber = tag - } - } else { - project.ext.revisionInfo = '?' - project.ext.revisionNumber = 1 - project.ext.versionNumber = 'SNAPSHOT' - } - - version = project.ext.versionNumber.startsWith('SNAPSHOT') ? "${project.ext.revisionNumber}" : project.ext.versionNumber - project.ext.revisionForPublication = project.ext.versionNumber.startsWith('SNAPSHOT') ? "${project.ext.revisionNumber}" : project.ext.versionNumber - project.ext.cleanFlag = calculateCleanFlag() - def buildInfo = "${project.ext.versionNumber}::${project.ext.revisionInfo}::${project.ext.cleanFlag}" - println "BUILD INFO for $project: $buildInfo" - def targetsDist = 'targets/dist' - def distFolder = new File("${project.projectDir}/$targetsDist") - distFolder.deleteDir() - distFolder.mkdirs() - file("${project.projectDir}/$targetsDist/BUILD-${project.name}.INFO") << buildInfo -} - -calculateBuildInfo() - -group='cisd' - -task checkRestrictions(type: Exec, dependsOn: [classes, testClasses]) { - doFirst { - def cp = configurations.testCompile.filter({ f -> f.name.startsWith('restrictionchecker') || f.name.startsWith('bcel')}).asPath - def cmd = ['java', '-cp', cp, 'ch.rinn.restrictions.RestrictionChecker', '-r', sourceSets.main.output.classesDir] - if (sourceSets.test.output.classesDir.exists()) { - cmd.add(sourceSets.test.output.classesDir) - } - cmd.add('-cp') - cmd.add(sourceSets.main.output.classesDir) - if (sourceSets.test.output.classesDir.exists()) { - cmd.add(sourceSets.test.output.classesDir) - } - cmd.add(configurations.testCompile.asPath) - commandLine cmd - } -} - -def deleteSymbolicLinksRecursively(file) { - def absolutePath = file.getAbsolutePath() - def canonicalPath = file.getCanonicalPath() - if (absolutePath.equals(canonicalPath) == false) { - file.delete(); - } else if (file.isDirectory()) { - File[] files = file.listFiles() - for (File child : files) { - deleteSymbolicLinksRecursively(child) - } - } -} - -task deleteSymLinks { - doFirst { - println "DELETE SYM LINKS in $buildDir" - deleteSymbolicLinksRecursively buildDir - } -} - -clean.dependsOn deleteSymLinks - -test { - useTestNG() - options.suites('sourceTest/java/tests.xml') - - systemProperty "ant.project.name", project.name - - maxHeapSize = "8192m" - jvmArgs '-XX:MaxPermSize=1024m', '-Duser.timezone=Europe/Zurich' - - testLogging.showStandardStreams = true - ignoreFailures = true -} -test.dependsOn checkRestrictions - -dependencies { - ecj "eclipse:ecj:+" -} - -compileJava { - options.encoding = 'utf-8' - options.fork = true - doFirst { - options.forkOptions.with { - executable = 'java' - jvmArgs = createJvmArgs() - } - } -} - -def createJvmArgs() { - def args = ['-cp', configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn'] - return args -} - -processTestResources { - fileMode=0666 -} - -apply plugin: 'eclipse' - -eclipse { - classpath { - downloadSources=true - defaultOutputDir = file('targets/classes') - } -} - -eclipse.classpath.file { - whenMerged{ classpath -> - def projectRefs = classpath.entries.findAll{entry -> entry.kind =='src' && entry.path.startsWith('/')} - classpath.entries.removeAll(projectRefs) - classpath.entries.addAll(projectRefs) - } -} - -task testJar(type: Jar, dependsOn: testClasses) { - baseName = "test-${project.archivesBaseName}" - from sourceSets.test.output -} - -task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource -} - -compileJava.dependsOn sourcesJar - -artifacts { - tests testJar -} - -artifacts { - archives sourcesJar -} - -task compileDependencies(type: Copy) { - into "$buildDir/output/compile-dependencies" - from configurations.compile -} - -task runtimeDependencies(type: Copy) { - into "$buildDir/output/runtime-dependencies" - from configurations.runtime -} - -task testCompileDependencies(type: Copy) { - into "$buildDir/output/testCompile-dependencies" - from configurations.testCompile -} - -task testRuntimeDependencies(type: Copy) { - into "$buildDir/output/testRuntime-dependencies" - from configurations.testRuntime -} - -task checkDependencies(dependsOn: classes) << { - ant.taskdef(name: 'dependencychecker', classname: 'classycle.ant.DependencyCheckingTask', classpath: configurations.testRuntime.asPath) - ant.dependencychecker( - definitionFile: 'resource/dependency-structure.ddf', - failOnUnwantedDependencies: 'true', - mergeInnerClasses: 'true') { - fileset(dir: "${buildDir}", includes: "**/*.class") - } -} - -apply plugin: 'ivy-publish' -if (hasProperty('ivyRepository') == false || ''.equals(project.ivyRepository)) -{ - project.ext.ivyRepository = "${project.projectDir}/../ivy-repository" -} -publishing { - - repositories { - ivy { - ivyPattern "file://${project.ivyRepository}/[organisation]/[module]/[revision]/ivy.xml" - artifactPattern "file://${project.ivyRepository}/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" - } - } -} - -publish { - dependsOn build -} - -if (JavaVersion.current().isJava8Compatible()) { - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - } -} diff --git a/lib-base/repository.gradle b/lib-base/repository.gradle deleted file mode 100644 index ca7ada3c059ee0c8311659f1ba8911ffac513f34..0000000000000000000000000000000000000000 --- a/lib-base/repository.gradle +++ /dev/null @@ -1,10 +0,0 @@ -ext.repositoryConfig = { - ivy { - ivyPattern "${project.projectDir}/../ivy-repository/[organisation]/[module]/[revision]/ivy.xml" - artifactPattern "${project.projectDir}/../ivy-repository/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" - } - ivy { - ivyPattern "http://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/[organisation]/[module]/[revision]/ivy.xml" - artifactPattern "http://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" - } -} diff --git a/lib-base/source/java/ch/systemsx/cisd/base/unix/Posix.java b/lib-base/source/java/ch/systemsx/cisd/base/unix/Posix.java new file mode 100644 index 0000000000000000000000000000000000000000..80bb928d4668a65d9a69c2d0c1b9e1806eda6d90 --- /dev/null +++ b/lib-base/source/java/ch/systemsx/cisd/base/unix/Posix.java @@ -0,0 +1,150 @@ +/* + * Copyright ETH 2023 Zürich, Scientific IT Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ch.systemsx.cisd.base.unix; + +import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; +import com.sun.security.auth.module.UnixSystem; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +public class Posix +{ + // Available on unix systems JDK 11 onwards + private static UnixSystem unixSystem = new com.sun.security.auth.module.UnixSystem(); + + // + // User Functions + // + + public static int getUid() + { + return (int) unixSystem.getUid(); + } + + public static int getGid() + { + return (int) unixSystem.getGid(); + } + + // + // File functions + // + + private static Set<PosixFilePermission> allPermissionsMode = Set.of(PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_WRITE, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_WRITE, + PosixFilePermission.OTHERS_EXECUTE); + + public static final void setAccessMode(String fileName, short mode) throws IOExceptionUnchecked + { + if (fileName == null) + { + throw new NullPointerException("fileName"); + } + + if (mode != 777) { + throw new IOExceptionUnchecked("Unsupported unix file permission mode: " + mode); + } + + try + { + Files.setPosixFilePermissions(Path.of(fileName), allPermissionsMode); + } catch (IOException e) + { + throw new IOExceptionUnchecked(e); + } + } + + /** + * Creates a hard link <var>linkName</var> that points to <var>fileName</var>. + * + * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because <var>linkName</var> already exists or <var>fileName</var> does + * not exist. + */ + public static final void createHardLink(String fileName, String linkName) + throws IOExceptionUnchecked + { + if (fileName == null) + { + throw new NullPointerException("fileName"); + } + if (linkName == null) + { + throw new NullPointerException("linkName"); + } + link(fileName, linkName); + } + + /** + * Creates a symbolic link <var>linkName</var> that points to <var>fileName</var>. + * + * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because <var>linkName</var> already exists. + */ + public static final void createSymbolicLink(String fileName, String linkName) + throws IOExceptionUnchecked + { + if (fileName == null) + { + throw new NullPointerException("fileName"); + } + if (linkName == null) + { + throw new NullPointerException("linkName"); + } + + symlink(fileName, linkName); + } + + /* + * This method manages symbolic link creation using NIO API. + */ + public static final void symlink(String fileName, String linkName) throws IOExceptionUnchecked { + try { + Path file = Path.of(fileName); + Path link = Path.of(linkName); + Path relativeFilePath = link.getParent().relativize(file); // Relative path to the file from the link + Files.createDirectories(link.getParent()); // Create any missing folder on the directory hierarchy leading to folder that will contain the link + Files.createSymbolicLink(link, relativeFilePath); // Creates the link + } catch (IOException exception) { + throw new IOExceptionUnchecked(exception); + } + } + + /* + * This method manages link creation using NIO API. + */ + public static final void link(String fileName, String linkName) throws IOExceptionUnchecked { + try { + Path file = Path.of(fileName); + Path link = Path.of(linkName); + Path relativeFilePath = link.getParent().relativize(file); // Relative path to the file from the link + Files.createDirectories(link.getParent()); // Create any missing folder on the directory hierarchy leading to folder that will contain the link + Files.createLink(link, relativeFilePath); // Creates the link + } catch (IOException exception) { + throw new IOExceptionUnchecked(exception); + } + } + +}