-
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..5a05248
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml
deleted file mode 100644
index 153a060..0000000
--- a/.idea/libraries/bld.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml
deleted file mode 100644
index 99cc0c0..0000000
--- a/.idea/libraries/compile.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml
deleted file mode 100644
index d4069f2..0000000
--- a/.idea/libraries/runtime.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml
deleted file mode 100644
index 57ed5ef..0000000
--- a/.idea/libraries/test.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 2adb169..794aa67 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,27 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 55adcb9..b65155f 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,8 +2,16 @@
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/pinboard-poster-samples-kotlin.iml b/.idea/modules/pinboard-poster-samples-kotlin.iml
new file mode 100644
index 0000000..16c524b
--- /dev/null
+++ b/.idea/modules/pinboard-poster-samples-kotlin.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/pinboard-poster_main.iml b/.idea/modules/pinboard-poster_main.iml
new file mode 100644
index 0000000..1155021
--- /dev/null
+++ b/.idea/modules/pinboard-poster_main.iml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/pinboard-poster_test.iml b/.idea/modules/pinboard-poster_test.iml
new file mode 100644
index 0000000..974f7f2
--- /dev/null
+++ b/.idea/modules/pinboard-poster_test.iml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/samples-java.iml b/.idea/modules/samples-java.iml
new file mode 100644
index 0000000..19b4065
--- /dev/null
+++ b/.idea/modules/samples-java.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/samples-java_main.iml b/.idea/modules/samples-java_main.iml
new file mode 100644
index 0000000..ee0308a
--- /dev/null
+++ b/.idea/modules/samples-java_main.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/samples-java_test.iml b/.idea/modules/samples-java_test.iml
new file mode 100644
index 0000000..3914650
--- /dev/null
+++ b/.idea/modules/samples-java_test.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/gradle/kotlin/.idea/kotlin.iml b/.idea/modules/samples-kotlin.iml
similarity index 82%
rename from examples/gradle/kotlin/.idea/kotlin.iml
rename to .idea/modules/samples-kotlin.iml
index d6ebd48..813d9e8 100644
--- a/examples/gradle/kotlin/.idea/kotlin.iml
+++ b/.idea/modules/samples-kotlin.iml
@@ -2,7 +2,7 @@
-
+
diff --git a/.idea/modules/samples-kotlin_main.iml b/.idea/modules/samples-kotlin_main.iml
new file mode 100644
index 0000000..3525c23
--- /dev/null
+++ b/.idea/modules/samples-kotlin_main.iml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/samples-kotlin_test.iml b/.idea/modules/samples-kotlin_test.iml
new file mode 100644
index 0000000..5245859
--- /dev/null
+++ b/.idea/modules/samples-kotlin_test.iml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 64767c7..a3d4392 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,12 +1,25 @@
-
+4.0.0net.thauvin.erikpinboard-poster
- 1.2.1-SNAPSHOT
+ 1.0.1
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.14.2
+ compile
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ 1.3.31
+ compile
+
+ pinboard-poster
- A small library for posting to Pinboard
+ Pinboard Poster for Kotlin/Javahttps://github.com/ethauvin/pinboard-poster
@@ -14,44 +27,11 @@
https://opensource.org/licenses/BSD-3-Clause
-
-
- org.jetbrains.kotlin
- kotlin-stdlib
- 2.1.20
- compile
-
-
- org.jetbrains.kotlin
- kotlin-stdlib-common
- 2.1.20
- compile
-
-
- org.jetbrains.kotlin
- kotlin-stdlib-jdk8
- 2.1.20
- compile
-
-
- com.squareup.okhttp3
- okhttp
- 4.12.0
- compile
-
-
- com.squareup.okhttp3
- logging-interceptor
- 4.12.0
- compile
-
- ethauvinErik C. Thauvinerik@thauvin.net
- https://erik.thauvin.net/
@@ -59,4 +39,8 @@
scm:git:git@github.com:ethauvin/pinboard-poster.githttps://github.com/ethauvin/pinboard-poster
+
+ GitHub
+ https://github.com/ethauvin/pinboard-poster/issues
+
diff --git a/preflightcheck.sh b/preflightcheck.sh
new file mode 100644
index 0000000..26b8aa8
--- /dev/null
+++ b/preflightcheck.sh
@@ -0,0 +1,213 @@
+#!/bin/bash
+
+# set source and test locations
+src="src/main/kotlin/net/thauvin/erik/pinboard"
+test="src/main/kotlin/net/thauvin/erik/pinboard"
+# e.g: .java, .kt, etc.
+ext=".kt"
+java8=true
+# e.g:
+declare -a examples=(
+ "samples/java run"
+ "samples/kotlin run")
+# e.g: empty or javadoc, etc.
+gradle_doc="dokka"
+# e.g. empty or sonarqube
+gradle_sonar="sonarqube"
+# gradle options for examples
+gradle_opts="--console=plain --no-build-cache --no-daemon"
+# maven arguments for examples
+maven_args=""
+
+#
+# Version: 1.1.4
+#
+
+if [ "$java8" = true ]
+then
+ export JAVA_HOME="$JAVA8_HOME"
+ export PATH="$(cygpath "$JAVA_HOME")/bin:$PATH"
+fi
+
+pwd=$PWD
+red=$(tput setaf 1)
+cyan=$(tput setaf 6)
+std=$(tput sgr0)
+date=$(date +%Y)
+
+pause() {
+ read -p "Press [Enter] key to continue..."
+}
+
+checkCopyright() {
+ if [ "$(grep -c "$date" "$1")" -eq 0 ]
+ then
+ echo -e " Invalid: ${red}$f${std}"
+ else
+ echo -e " Checked: $1"
+ fi
+}
+
+runGradle() {
+ cd "$1" || exit 1
+ clear
+ reset
+ echo -e "> Project: ${cyan}${1}${std} [Gradle]"
+ shift
+ ./gradlew $@ || exit 1
+ pause
+ cd "$pwd"
+}
+
+runKobalt() {
+ cd "$1" || exit 1
+ if [ -f kobalt/src/Build.kt ]
+ then
+ clear
+ reset
+ echo -e "> Project: ${cyan}${1}${std} [Kobalt]"
+ shift
+ ./kobaltw $@ || exit 1
+ pause
+ fi
+ cd "$pwd"
+}
+
+runMaven() {
+ cd "$1" || exit 1
+ if [ -f pom.xml ]
+ then
+ clear
+ reset
+ echo -e "> Project: ${cyan}${1}${std} [Maven]"
+ shift
+ mvn $@ || exit 1
+ pause
+ fi
+ cd "$pwd"
+}
+
+updateWrappers() {
+ clear
+ ./updatewrappers.sh
+ pause
+}
+
+checkDeps() {
+ clear
+ echo -e "${cyan}Checking depencencies...${std}"
+ gradle --console=plain dU || exit 1
+ read -p "Check Examples depencencies? [y/n] " cont
+ clear
+ case $cont in
+ [Nn] ) return ;;
+ * ) for ex in "${!examples[@]}"
+ do
+ runGradle $(echo "${examples[ex]}" | cut -d " " -f 1) dU
+ runKobalt $(echo "${examples[ex]}" | cut -d " " -f 1) checkVersions
+ runMaven $(echo "${examples[ex]}" | cut -d " " -f 1) versions:display-dependency-updates
+ if [ "$ex" -eq "${#examples}" ]
+ then
+ read -p "Continue? [y/n]: " cont
+ clear
+ case $cont in
+ * ) continue ;;
+ [Nn] ) return ;;
+ esac
+ fi
+ done ;;
+ esac
+}
+
+gradleCheck() {
+ clear
+ echo -e "${cyan}Checking Gradle build....${std}"
+ gradle $gradle_opts clean check $gradle_doc $gradle_sonar || exit 1
+ pause
+}
+
+runExamples() {
+ for ex in "${!examples[@]}"
+ do
+ runGradle ${examples[ex]} clean $gradle_opts
+ runKobalt ${examples[ex]} clean
+ runMaven $(echo "${examples[ex]}" | cut -d " " -f 1) clean $maven_args
+ done
+}
+
+examplesMenu() {
+ clear
+ echo -e "${cyan}Examples${std}"
+ for ex in "${!examples[@]}"
+ do
+ printf ' %d. %s\n' $(($ex + 1)) $(echo "${examples[ex]}" | cut -d " " -f 1)
+ done
+ echo " $((${#examples[@]} + 1)). Run All Examples"
+ read -p "Enter choice [1-${#examples[@]}]: " choice
+ clear
+ case $choice in
+ [0-9] ) if [ "$choice" -gt "${#examples[@]}" ]
+ then
+ runExamples
+ examplesMenu
+ else
+ runGradle ${examples[$(($choice - 1))]}
+ runKobalt ${examples[$(($choice - 1))]}
+ runMaven $(echo "${examples[$(($choice - 1))]}" | cut -d " " -f 1) $maven_args
+ examplesMenu
+ fi ;;
+ * ) return ;;
+ esac
+}
+
+validateCopyrights() {
+ clear
+ echo -e "${cyan}Validating copyrights...${std}"
+ for f in "LICENSE.TXT" ${src}/*${ext} ${test}/*${ext}
+ do
+ if [ -f "$f" ]
+ then
+ checkCopyright "$f"
+ fi
+ done
+ pause
+}
+
+everything() {
+ updateWrappers
+ checkDeps
+ gradleCheck
+ runExamples
+ validateCopyrights
+}
+
+showMenu() {
+ clear
+ echo "${cyan}Preflight Check${std}"
+ echo " 1. Update Wrappers"
+ echo " 2. Check Dependencies"
+ echo " 3. Check Gradle Build"
+ echo " 4. Run Examples"
+ echo " 5. Validate Copyrights"
+ echo " 6. Check Everything"
+}
+
+readOptions() {
+ local choice
+ read -p "Enter choice [1-6]: " choice
+ case $choice in
+ 1) updateWrappers ;;
+ 2) checkDeps ;;
+ 3) gradleCheck ;;
+ 4) examplesMenu ;;
+ 5) validateCopyrights ;;
+ 6) everything ;;
+ *) exit 0 ;;
+ esac
+}
+
+while true
+do
+ showMenu
+ readOptions
+done
diff --git a/samples/examples.sh b/samples/examples.sh
new file mode 100644
index 0000000..99926d3
--- /dev/null
+++ b/samples/examples.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Version 1.0
+
+if [ $# -eq 0 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# set the examples directories
+declare -a examples=(
+ "java"
+ "kotlin")
+
+dir=$(dirname "$(readlink -f "$0")")
+cyan=$(tput setaf 6)
+normal=$(tput sgr0)
+
+i=0
+for ex in "${examples[@]}"; do
+ if [ $i -ne 0 ]
+ then
+ read -p "Press [Enter] key to continue..."
+ clear
+ fi
+ cd "$dir/$ex" || exit 1
+ echo "> Project: ${cyan}${ex}${normal}"
+ ./gradlew --console=plain --no-build-cache clean "$@" || exit 1
+ (( i++ ))
+done
diff --git a/examples/gradle/java/.editorconfig b/samples/java/.editorconfig
similarity index 100%
rename from examples/gradle/java/.editorconfig
rename to samples/java/.editorconfig
diff --git a/examples/gradle/java/.gitignore b/samples/java/.gitignore
similarity index 100%
rename from examples/gradle/java/.gitignore
rename to samples/java/.gitignore
diff --git a/samples/java/build.gradle b/samples/java/build.gradle
new file mode 100644
index 0000000..ec04ddc
--- /dev/null
+++ b/samples/java/build.gradle
@@ -0,0 +1,17 @@
+plugins {
+ id 'java'
+ id 'application'
+}
+
+defaultTasks 'run'
+
+mainClassName = 'net.thauvin.erik.pinboard.samples.JavaExample'
+
+dependencies {
+ compile 'net.thauvin.erik:pinboard-poster:1.0.1'
+}
+
+repositories {
+ mavenLocal()
+ jcenter()
+}
diff --git a/samples/java/gradle/wrapper/gradle-wrapper.jar b/samples/java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
Binary files /dev/null and b/samples/java/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/examples/gradle/kotlin/gradle/wrapper/gradle-wrapper.properties b/samples/java/gradle/wrapper/gradle-wrapper.properties
similarity index 74%
rename from examples/gradle/kotlin/gradle/wrapper/gradle-wrapper.properties
rename to samples/java/gradle/wrapper/gradle-wrapper.properties
index ca025c8..f4d7b2b 100644
--- a/examples/gradle/kotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/java/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/samples/java/gradlew b/samples/java/gradlew
new file mode 100755
index 0000000..b0d6d0a
--- /dev/null
+++ b/samples/java/gradlew
@@ -0,0 +1,188 @@
+#!/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
+#
+# 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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+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='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# 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
+ ;;
+ 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" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+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
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/examples/gradle/java/gradlew.bat b/samples/java/gradlew.bat
similarity index 69%
rename from examples/gradle/java/gradlew.bat
rename to samples/java/gradlew.bat
index db3a6ac..9991c50 100644
--- a/examples/gradle/java/gradlew.bat
+++ b/samples/java/gradlew.bat
@@ -5,7 +5,7 @@
@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 http://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,
@@ -13,10 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
-@rem SPDX-License-Identifier: Apache-2.0
-@rem
-@if "%DEBUG%"=="" @echo off
+@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -27,14 +25,10 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
+if "%DIRNAME%" == "" set DIRNAME=.
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"
@@ -43,13 +37,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
+if "%ERRORLEVEL%" == "0" goto init
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
+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
@@ -57,36 +51,48 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto execute
+if exist "%JAVA_EXE%" goto init
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
+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
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
:execute
@rem Setup the command line
-set CLASSPATH=
-
+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%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
+if "%ERRORLEVEL%"=="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%
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/examples/gradle/java/settings.gradle b/samples/java/settings.gradle
similarity index 84%
rename from examples/gradle/java/settings.gradle
rename to samples/java/settings.gradle
index 87b714a..e7ecd5d 100644
--- a/examples/gradle/java/settings.gradle
+++ b/samples/java/settings.gradle
@@ -7,4 +7,4 @@
* in the user guide at https://docs.gradle.org/4.8/userguide/multi_project_builds.html
*/
-rootProject.name = 'pinboard-poster-examples-gradle-java'
+rootProject.name = 'samples-java'
diff --git a/samples/java/src/main/java/net/thauvin/erik/pinboard/samples/JavaExample.java b/samples/java/src/main/java/net/thauvin/erik/pinboard/samples/JavaExample.java
new file mode 100644
index 0000000..e6da4fc
--- /dev/null
+++ b/samples/java/src/main/java/net/thauvin/erik/pinboard/samples/JavaExample.java
@@ -0,0 +1,71 @@
+/*
+ * JavaExample.java
+ *
+ * Copyright (c) 2017-2018, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of this project nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.thauvin.erik.pinboard.samples;
+
+import net.thauvin.erik.pinboard.PinboardPoster;
+
+import java.nio.file.Paths;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JavaExample {
+ public static void main(String[] args) {
+ final String url = "http://www.example.com/pinboard";
+ final PinboardPoster poster;
+
+ if (args.length == 1) {
+ // API Token is an argument
+ poster = new PinboardPoster(args[0]);
+ } else {
+ // API Token is in local.properties or PINBOARD_API_TOKEN environment variable
+ poster = new PinboardPoster(Paths.get("local.properties"));
+ }
+
+ // Set logging levels
+ final ConsoleHandler consoleHandler = new ConsoleHandler();
+ consoleHandler.setLevel(Level.FINE);
+ final Logger logger = poster.getLogger();
+ logger.addHandler(consoleHandler);
+ logger.setLevel(Level.FINE);
+
+ // Add Pin
+ if (poster.addPin(url, "Testing", "Extended test", "test java")) {
+ System.out.println("Added: " + url);
+ }
+
+ // Delete Pin
+ if (poster.deletePin(url)) {
+ System.out.println("Deleted: " + url);
+ }
+ }
+}
diff --git a/examples/gradle/kotlin/.editorconfig b/samples/kotlin/.editorconfig
similarity index 100%
rename from examples/gradle/kotlin/.editorconfig
rename to samples/kotlin/.editorconfig
diff --git a/examples/gradle/kotlin/.gitignore b/samples/kotlin/.gitignore
similarity index 100%
rename from examples/gradle/kotlin/.gitignore
rename to samples/kotlin/.gitignore
diff --git a/samples/kotlin/build.gradle.kts b/samples/kotlin/build.gradle.kts
new file mode 100644
index 0000000..1d142ff
--- /dev/null
+++ b/samples/kotlin/build.gradle.kts
@@ -0,0 +1,19 @@
+plugins {
+ application
+ kotlin("jvm") version "1.3.0"
+}
+
+defaultTasks(ApplicationPlugin.TASK_RUN_NAME)
+
+dependencies {
+ compile("net.thauvin.erik:pinboard-poster:1.0.1")
+}
+
+application {
+ mainClassName = "net.thauvin.erik.pinboard.samples.KotlinExampleKt"
+}
+
+repositories {
+ mavenLocal()
+ jcenter()
+}
diff --git a/samples/kotlin/gradle/wrapper/gradle-wrapper.jar b/samples/kotlin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
Binary files /dev/null and b/samples/kotlin/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/samples/kotlin/gradle/wrapper/gradle-wrapper.properties b/samples/kotlin/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..f4d7b2b
--- /dev/null
+++ b/samples/kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/samples/kotlin/gradlew b/samples/kotlin/gradlew
new file mode 100755
index 0000000..b0d6d0a
--- /dev/null
+++ b/samples/kotlin/gradlew
@@ -0,0 +1,188 @@
+#!/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
+#
+# 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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+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='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# 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
+ ;;
+ 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" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+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
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/samples/kotlin/gradlew.bat b/samples/kotlin/gradlew.bat
new file mode 100644
index 0000000..9991c50
--- /dev/null
+++ b/samples/kotlin/gradlew.bat
@@ -0,0 +1,100 @@
+@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 http://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=.
+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="-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%" == "0" goto init
+
+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 init
+
+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
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+: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 %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="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!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/kotlin/kobalt/src/Build.kt b/samples/kotlin/kobalt/src/Build.kt
new file mode 100644
index 0000000..5f0fc9e
--- /dev/null
+++ b/samples/kotlin/kobalt/src/Build.kt
@@ -0,0 +1,29 @@
+import com.beust.kobalt.*
+import com.beust.kobalt.plugin.application.*
+import com.beust.kobalt.plugin.packaging.assemble
+
+// ./kobaltw run
+
+val bs = buildScript {
+ repos(localMaven())
+}
+
+val p = project {
+ name = "KotlinExample"
+ version = "0.1"
+
+ dependencies {
+ compile("net.thauvin.erik:pinboard-poster:1.0.1")
+ }
+
+ assemble {
+ jar {
+
+ }
+ }
+
+ application {
+ ignoreErrorStream = true
+ mainClass = "net.thauvin.erik.pinboard.samples.KotlinExampleKt"
+ }
+}
diff --git a/samples/kotlin/kobalt/wrapper/kobalt-wrapper.jar b/samples/kotlin/kobalt/wrapper/kobalt-wrapper.jar
new file mode 100644
index 0000000..0721eec
Binary files /dev/null and b/samples/kotlin/kobalt/wrapper/kobalt-wrapper.jar differ
diff --git a/samples/kotlin/kobalt/wrapper/kobalt-wrapper.properties b/samples/kotlin/kobalt/wrapper/kobalt-wrapper.properties
new file mode 100644
index 0000000..bdce6e3
--- /dev/null
+++ b/samples/kotlin/kobalt/wrapper/kobalt-wrapper.properties
@@ -0,0 +1 @@
+kobalt.version=1.0.123
diff --git a/samples/kotlin/kobaltw b/samples/kotlin/kobaltw
new file mode 100755
index 0000000..c5186d5
--- /dev/null
+++ b/samples/kotlin/kobaltw
@@ -0,0 +1,2 @@
+#!/usr/bin/env sh
+java -jar "`dirname "$0"`/kobalt/wrapper/kobalt-wrapper.jar" $*
diff --git a/samples/kotlin/kobaltw.bat b/samples/kotlin/kobaltw.bat
new file mode 100644
index 0000000..d578071
--- /dev/null
+++ b/samples/kotlin/kobaltw.bat
@@ -0,0 +1,4 @@
+@echo off
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+java -jar "%DIRNAME%/kobalt/wrapper/kobalt-wrapper.jar" %*
diff --git a/samples/kotlin/settings.gradle.kts b/samples/kotlin/settings.gradle.kts
new file mode 100644
index 0000000..28613c7
--- /dev/null
+++ b/samples/kotlin/settings.gradle.kts
@@ -0,0 +1 @@
+rootProject.name = "samples-kotlin"
diff --git a/samples/kotlin/src/main/kotlin/net/thauvin/erik/pinboard/samples/KotlinExample.kt b/samples/kotlin/src/main/kotlin/net/thauvin/erik/pinboard/samples/KotlinExample.kt
new file mode 100644
index 0000000..77c8ba5
--- /dev/null
+++ b/samples/kotlin/src/main/kotlin/net/thauvin/erik/pinboard/samples/KotlinExample.kt
@@ -0,0 +1,65 @@
+/*
+ * KotlinExample.kt
+ *
+ * Copyright (c) 2017-2018, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of this project nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.thauvin.erik.pinboard.samples
+
+import net.thauvin.erik.pinboard.PinboardPoster
+import java.nio.file.Paths
+import java.util.logging.ConsoleHandler
+import java.util.logging.Level
+
+fun main(args: Array) {
+ val url = "http://www.example.com/pinboard"
+
+ val poster = if (args.size == 1) {
+ // API Token is an argument
+ PinboardPoster(args[0])
+ } else {
+ // API Token is in local.properties or PINBOARD_API_TOKEN environment variable
+ PinboardPoster(Paths.get("local.properties"))
+ }
+
+ // Set logging levels
+ with(poster.logger) {
+ addHandler(ConsoleHandler().apply { level = Level.FINE })
+ level = Level.FINE
+ }
+
+ // Add Pin
+ if (poster.addPin(url, "Testing", "Extended test", "test kotlin")) {
+ println("Added: $url")
+ }
+
+ // Delete Pin
+ if (poster.deletePin(url)) {
+ println("Deleted: $url")
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1 @@
+
diff --git a/sonar-project.properties b/sonar-project.properties
deleted file mode 100644
index 20487a7..0000000
--- a/sonar-project.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-sonar.organization=ethauvin-github
-sonar.projectKey=ethauvin_pinboard-poster
-sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml
-sonar.sources=src/main/kotlin/
-sonar.tests=src/test/kotlin/
-sonar.java.binaries=build/main,build/test
-sonar.java.libraries=lib/compile/*.jar
diff --git a/src/bld/java/net/thauvin/erik/pinboard/PinboardPosterBuild.java b/src/bld/java/net/thauvin/erik/pinboard/PinboardPosterBuild.java
deleted file mode 100644
index 7dfc1d4..0000000
--- a/src/bld/java/net/thauvin/erik/pinboard/PinboardPosterBuild.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * PinboardPosterBuild.java
- *
- * Copyright (c) 2017-2025, Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package net.thauvin.erik.pinboard;
-
-import rife.bld.BuildCommand;
-import rife.bld.Project;
-import rife.bld.extension.CompileKotlinOperation;
-import rife.bld.extension.DetektOperation;
-import rife.bld.extension.DokkaOperation;
-import rife.bld.extension.JacocoReportOperation;
-import rife.bld.extension.dokka.LoggingLevel;
-import rife.bld.extension.dokka.OutputFormat;
-import rife.bld.extension.kotlin.CompileOptions;
-import rife.bld.operations.exceptions.ExitStatusException;
-import rife.bld.publish.PomBuilder;
-import rife.bld.publish.PublishDeveloper;
-import rife.bld.publish.PublishLicense;
-import rife.bld.publish.PublishScm;
-import rife.tools.exceptions.FileUtilsErrorException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static rife.bld.dependencies.Repository.*;
-import static rife.bld.dependencies.Scope.compile;
-import static rife.bld.dependencies.Scope.test;
-
-public class PinboardPosterBuild extends Project {
- final File srcMainKotlin = new File(srcMainDirectory(), "kotlin");
-
- public PinboardPosterBuild() {
- pkg = "net.thauvin.erik";
- name = "pinboard-poster";
- version = version(1, 2, 1, "SNAPSHOT");
-
- mainClass = pkg + ".PinboardPoster";
-
- javaRelease = 11;
- downloadSources = true;
- autoDownloadPurge = true;
- repositories = List.of(MAVEN_LOCAL, MAVEN_CENTRAL);
-
- final var okHttp = version(4, 12, 0);
- final var kotlin = version(2, 1, 20);
- scope(compile)
- // Kotlin
- .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))
- .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin))
- .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin))
- // OkHttp
- .include(dependency("com.squareup.okhttp3", "okhttp", okHttp))
- .include(dependency("com.squareup.okhttp3", "logging-interceptor", okHttp));
- scope(test)
- .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
- .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2)))
- .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2)))
- .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 2)));
-
- publishOperation()
- .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location())
- .withCredentials(property("sonatype.user"), property("sonatype.password"))
- : repository(SONATYPE_RELEASES_LEGACY.location())
- .withCredentials(property("sonatype.user"), property("sonatype.password")))
- .repository(repository("github"))
- .info()
- .groupId(pkg)
- .artifactId(name)
- .description("A small library for posting to Pinboard")
- .url("https://github.com/ethauvin/" + name)
- .developer(new PublishDeveloper()
- .id("ethauvin")
- .name("Erik C. Thauvin")
- .email("erik@thauvin.net")
- .url("https://erik.thauvin.net/")
- )
- .license(new PublishLicense()
- .name("BSD 3-Clause")
- .url("https://opensource.org/licenses/BSD-3-Clause")
- )
- .scm(new PublishScm()
- .connection("scm:git:https://github.com/ethauvin/" + name + ".git")
- .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git")
- .url("https://github.com/ethauvin/" + name)
- )
- .signKey(property("sign.key"))
- .signPassphrase(property("sign.passphrase"));
-
- jarSourcesOperation().sourceDirectories(srcMainKotlin);
- }
-
- public static void main(final String[] args) {
- // Enable detailed logging for the extensions
- var level = Level.ALL;
- var logger = Logger.getLogger("rife.bld.extension");
- var consoleHandler = new ConsoleHandler();
-
- consoleHandler.setLevel(level);
- logger.addHandler(consoleHandler);
- logger.setLevel(level);
- logger.setUseParentHandlers(false);
-
- new PinboardPosterBuild().start(args);
- }
-
- @BuildCommand(summary = "Compiles the Kotlin project")
- @Override
- public void compile() throws Exception {
- new CompileKotlinOperation()
- .fromProject(this)
- .compileOptions(new CompileOptions().verbose(true))
- .execute();
- }
-
- @BuildCommand(summary = "Checks source with Detekt")
- public void detekt() throws ExitStatusException, IOException, InterruptedException {
- new DetektOperation()
- .fromProject(this)
- .baseline("config/detekt/baseline.xml")
- .execute();
- }
-
- @BuildCommand(value = "detekt-baseline", summary = "Creates the Detekt baseline")
- public void detektBaseline() throws ExitStatusException, IOException, InterruptedException {
- new DetektOperation()
- .fromProject(this)
- .baseline("config/detekt/baseline.xml")
- .createBaseline(true)
- .execute();
- }
-
- @BuildCommand(summary = "Generates JaCoCo Reports")
- public void jacoco() throws Exception {
- new JacocoReportOperation()
- .fromProject(this)
- .sourceFiles(srcMainKotlin)
- .execute();
- }
-
- @Override
- public void javadoc() throws ExitStatusException, IOException, InterruptedException {
- new DokkaOperation()
- .fromProject(this)
- .loggingLevel(LoggingLevel.INFO)
- .moduleName("CryptoPrice")
- .moduleVersion(version.toString())
- .outputDir(new File(buildDirectory(), "javadoc"))
- .outputFormat(OutputFormat.JAVADOC)
- .execute();
- }
-
- @Override
- public void publish() throws Exception {
- super.publish();
- pomRoot();
- }
-
- @Override
- public void publishLocal() throws Exception {
- super.publishLocal();
- pomRoot();
- }
-
- @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory")
- public void pomRoot() throws FileUtilsErrorException {
- PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
- new File(workDirectory, "pom.xml"));
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/pinboard/PinConfig.kt b/src/main/kotlin/net/thauvin/erik/pinboard/PinConfig.kt
deleted file mode 100644
index a41e563..0000000
--- a/src/main/kotlin/net/thauvin/erik/pinboard/PinConfig.kt
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * PinConfig.kt
- *
- * Copyright (c) 2017-2025, Erik C. Thauvin (erik@thauvin.net)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of this project nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package net.thauvin.erik.pinboard
-
-import java.time.ZonedDateTime
-
-/**
- * Provides a builder to add a pin.
- *
- * Supports of all the [Pinboard API Parameters](https://pinboard.in/api/#posts_add).
- */
-class PinConfig private constructor(builder: Builder) {
- val url: String = builder.url
- val description: String = builder.description
- val extended = builder.extended
- val tags = builder.tags
- val dt = builder.dt
- val replace = builder.replace
- val shared = builder.shared
- val toRead = builder.toRead
-
- /**
- * Configures the parameters to add a pin.
- *
- * @param url The URL of the bookmark.
- * @param description The title of the bookmark.
- */
- data class Builder(var url: String, var description: String) {
- var extended: String = ""
- var tags: Array = emptyArray()
- var dt: ZonedDateTime = ZonedDateTime.now()
- var replace: Boolean = true
- var shared: Boolean = true
- var toRead: Boolean = false
-
- /**
- * The URL of the bookmark.
- */
- fun url(url: String): Builder = apply { this.url = url }
-
- /**
- * The title of the bookmark.
- */
- fun description(description: String): Builder = apply { this.description = description }
-
- /**
- * The description of the bookmark.
- */
- fun extended(extended: String): Builder = apply { this.extended = extended }
-
- /**
- * A list of up to 100 tags.
- */
- fun tags(vararg tag: String): Builder = apply { this.tags = tag }
-
- /**
- * The creation time of the bookmark.
- */
- fun dt(datetime: ZonedDateTime): Builder = apply { this.dt = datetime }
-
- /**
- * Replace any existing bookmark with the specified URL. Default `true`.
- */
- fun replace(replace: Boolean): Builder = apply { this.replace = replace }
-
- /**
- * Make bookmark public. Default is `true`.
- */
- fun shared(shared: Boolean): Builder = apply { this.shared = shared }
-
- /**
- * Mark the bookmark as unread. Default is `false`.
- */
- fun toRead(toRead: Boolean): Builder = apply { this.toRead = toRead }
-
- /**
- * Builds a new configuration.
- */
- fun build() = PinConfig(this)
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (javaClass != other?.javaClass) return false
-
- other as Builder
-
- if (url != other.url) return false
- if (description != other.description) return false
- if (extended != other.extended) return false
- if (!tags.contentEquals(other.tags)) return false
- if (dt != other.dt) return false
- if (replace != other.replace) return false
- if (shared != other.shared) return false
- if (toRead != other.toRead) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = url.hashCode()
- result = 31 * result + description.hashCode()
- result = 31 * result + extended.hashCode()
- result = 31 * result + tags.contentHashCode()
- result = 31 * result + dt.hashCode()
- result = 31 * result + replace.hashCode()
- result = 31 * result + shared.hashCode()
- result = 31 * result + toRead.hashCode()
- return result
- }
-
- override fun toString(): String {
- return "Builder(url='$url', description='$description', extended='$extended'," +
- "tags=${tags.contentToString()}, dt=$dt, replace=$replace, shared=$shared, toRead=$toRead)"
- }
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt b/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt
index 00d2cc1..ebcab40 100644
--- a/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt
+++ b/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt
@@ -1,7 +1,8 @@
/*
* PinboardPoster.kt
*
- * Copyright (c) 2017-2025, Erik C. Thauvin (erik@thauvin.net)
+ * Copyright (c) 2017-2019, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,21 +32,18 @@
package net.thauvin.erik.pinboard
-import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
-import okhttp3.logging.HttpLoggingInterceptor
import org.xml.sax.InputSource
import java.io.File
import java.io.IOException
import java.io.StringReader
-import java.net.URI
-import java.net.URISyntaxException
+import java.net.MalformedURLException
+import java.net.URL
import java.nio.file.Files
import java.nio.file.Path
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
-import java.util.*
+import java.util.Properties
import java.util.logging.Level
import java.util.logging.Logger
import javax.xml.parsers.DocumentBuilderFactory
@@ -54,7 +52,6 @@ import javax.xml.parsers.DocumentBuilderFactory
object Constants {
/** The Pinboard API endpoint URL. **/
const val API_ENDPOINT = "https://api.pinboard.in/v1/"
-
/** The API token environment variable. **/
const val ENV_API_TOKEN = "PINBOARD_API_TOKEN"
}
@@ -64,7 +61,7 @@ object Constants {
*
* @constructor Creates a new instance.
*
- * @author Erik C. Thauvin
+ * @author [Erik C. Thauvin](https://erik.thauvin.net/)
*/
open class PinboardPoster() {
/**
@@ -82,6 +79,7 @@ open class PinboardPoster() {
* @param properties The properties.
* @param key The property key.
*/
+ @Suppress("unused")
@JvmOverloads
constructor(properties: Properties, key: String = Constants.ENV_API_TOKEN) : this() {
apiToken = properties.getProperty(key, apiToken)
@@ -121,33 +119,10 @@ open class PinboardPoster() {
var apiEndPoint: String = Constants.API_ENDPOINT
/** The logger instance. **/
+ @Suppress("MemberVisibilityCanBePrivate")
val logger: Logger by lazy { Logger.getLogger(PinboardPoster::class.java.simpleName) }
- private val client by lazy {
- OkHttpClient.Builder().apply {
- if (logger.isLoggable(Level.FINE)) {
- addInterceptor(HttpLoggingInterceptor().apply {
- level = HttpLoggingInterceptor.Level.BODY
- })
- }
- }.build()
- }
-
- /**
- * Adds a bookmark to Pinboard using a [PinConfig] builder.
- */
- fun addPin(config: PinConfig): Boolean {
- return addPin(
- url = config.url,
- description = config.description,
- extended = config.extended,
- tags = config.tags,
- dt = config.dt,
- replace = config.replace,
- shared = config.shared,
- toRead = config.toRead
- )
- }
+ private val client by lazy { OkHttpClient() }
/**
* Adds a bookmark to Pinboard.
@@ -170,8 +145,8 @@ open class PinboardPoster() {
url: String,
description: String,
extended: String = "",
- vararg tags: String = emptyArray(),
- dt: ZonedDateTime = ZonedDateTime.now(),
+ tags: String = "",
+ dt: String = "",
replace: Boolean = true,
shared: Boolean = true,
toRead: Boolean = false
@@ -182,15 +157,15 @@ open class PinboardPoster() {
} else if (description.isBlank()) {
logger.severe("Please specify a valid description to pin: `$url`")
} else {
- val params = mapOf(
- "url" to url,
- "description" to description,
- "extended" to extended,
- "tags" to tags.joinToString(","),
- "dt" to DateTimeFormatter.ISO_INSTANT.format(dt.withNano(0)),
- "replace" to yesNo(replace),
- "shared" to yesNo(shared),
- "toread" to yesNo(toRead)
+ val params = listOf(
+ Pair("url", url),
+ Pair("description", description),
+ Pair("extended", extended),
+ Pair("tags", tags),
+ Pair("dt", dt),
+ Pair("replace", yesNo(replace)),
+ Pair("shared", yesNo(shared)),
+ Pair("toread", yesNo(toRead))
)
return executeMethod("posts/add", params)
}
@@ -213,14 +188,13 @@ open class PinboardPoster() {
if (!validateUrl(url)) {
logger.severe("Please specify a valid URL to delete.")
} else {
- return executeMethod("posts/delete", mapOf("url" to url))
+ return executeMethod("posts/delete", listOf(Pair("url", url)))
}
}
return false
}
- @Throws(IOException::class)
internal fun parseMethodResponse(method: String, response: String) {
val factory = DocumentBuilderFactory.newInstance().apply {
isValidating = false
@@ -237,63 +211,68 @@ open class PinboardPoster() {
try {
val document = factory.newDocumentBuilder().parse(InputSource(StringReader(response)))
- val code = document.getElementsByTagName("result")?.item(0)?.attributes?.getNamedItem("code")?.nodeValue
+ val code = document.getElementsByTagName("result")?.item(0)?.attributes?.getNamedItem(
+ "code")?.nodeValue
if (!code.isNullOrBlank()) {
throw IOException("An error has occurred while executing $method: $code")
} else {
throw IOException("An error has occurred while executing $method.")
}
- } catch (e: org.xml.sax.SAXException) {
+ } catch (e: Exception) {
throw IOException("Could not parse $method response.", e)
- } catch (e: IllegalArgumentException) {
- throw IOException("Invalid input source for $method response", e)
}
}
private fun cleanEndPoint(method: String): String {
- return if (apiEndPoint.last() == '/') {
+ return if (apiEndPoint.endsWith('/')) {
"$apiEndPoint$method"
} else {
"$apiEndPoint/$method"
}
}
- private fun executeMethod(method: String, params: Map): Boolean {
- try {
- val apiUrl = cleanEndPoint(method).toHttpUrlOrNull()
- if (apiUrl != null) {
- val httpUrl = apiUrl.newBuilder().apply {
- params.forEach {
- addQueryParameter(it.key, it.value)
- }
- addQueryParameter("auth_token", apiToken)
- }.build()
+ private fun executeMethod(method: String, params: List>): Boolean {
+ val apiUrl = HttpUrl.parse(cleanEndPoint(method))
+ if (apiUrl != null) {
+ val httpUrl = apiUrl.newBuilder().apply {
+ params.forEach {
+ addQueryParameter(it.first, it.second)
+ }
+ addQueryParameter("auth_token", apiToken)
+ }.build()
- val request = Request.Builder().url(httpUrl).build()
- client.newCall(request).execute().use { result ->
- result.body?.string()?.let { response ->
- if (response.contains("done")) {
- return true
- } else {
- parseMethodResponse(method, response)
- }
+ val request = Request.Builder().url(httpUrl).build()
+ val result = client.newCall(request).execute()
+
+ logHttp(method, "HTTP Result: ${result.code()}")
+
+ val response = result.body()?.string()
+
+ if (response != null) {
+ logHttp(method, "HTTP Response:\n$response")
+ if (response.contains("done")) {
+ return true
+ } else {
+ try {
+ parseMethodResponse(method, response)
+ } catch (e: IOException) {
+ logger.log(Level.SEVERE, e.message, e)
}
}
- } else {
- logger.severe("Invalid API end point: $apiEndPoint")
}
- } catch (e: IOException) {
- logger.log(Level.SEVERE, e.message, e)
+ } else {
+ logger.severe("Invalid API end point: $apiEndPoint")
}
return false
}
- /**
- * Ensures that the API token and end point are valid.
- */
- fun validate(): Boolean {
+ private fun logHttp(method: String, msg: String) {
+ logger.logp(Level.FINE, PinboardPoster::class.java.name, "executeMethod($method)", msg)
+ }
+
+ private fun validate(): Boolean {
var isValid = true
if (!apiToken.contains(':')) {
logger.severe("Please specify a valid API token. (eg. user:TOKEN)")
@@ -309,8 +288,8 @@ open class PinboardPoster() {
var isValid = url.isNotBlank()
if (isValid) {
try {
- URI(url)
- } catch (e: URISyntaxException) {
+ URL(url)
+ } catch (e: MalformedURLException) {
logger.log(Level.FINE, "Invalid URL: $url", e)
isValid = false
}
diff --git a/src/test/kotlin/net/thauvin/erik/pinboard/PinboardPosterTest.kt b/src/test/kotlin/net/thauvin/erik/pinboard/PinboardPosterTest.kt
index 9281df5..02687d1 100644
--- a/src/test/kotlin/net/thauvin/erik/pinboard/PinboardPosterTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/pinboard/PinboardPosterTest.kt
@@ -1,7 +1,8 @@
/*
* PinboardPosterTest.kt
*
- * Copyright (c) 2017-2025, Erik C. Thauvin (erik@thauvin.net)
+ * Copyright (c) 2017-2019, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,29 +32,23 @@
package net.thauvin.erik.pinboard
-import org.junit.jupiter.api.assertThrows
+import org.testng.Assert.assertFalse
+import org.testng.Assert.assertTrue
+import org.testng.Assert.expectThrows
+import org.testng.annotations.Test
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths
-import java.time.ZonedDateTime
-import java.util.*
-import java.util.logging.Level
-import kotlin.test.Test
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
+import java.util.Properties
class PinboardPosterTest {
- private val url = randomUrl()
+ private val url = "http://www.foo.com/"
private val desc = "This is a test."
private val localProps = Paths.get("local.properties")
- private val isCi = "true" == System.getenv("CI")
-
- private fun randomUrl(): String = "https://www.example.com/?random=" + (1000..10000).random()
@Test
fun testAddPin() {
var poster = PinboardPoster("")
- poster.logger.level = Level.FINE
assertFalse(poster.addPin(url, desc), "apiToken: ")
@@ -64,53 +59,7 @@ class PinboardPosterTest {
// assertFalse(poster.addPin(url, desc), "apiToken: ${poster.apiToken}")
poster = PinboardPoster(localProps)
- if (!isCi) {
- poster.logger.level = Level.FINE
- }
-
- assertTrue(poster.validate(), "validate()")
-
- assertTrue(poster.addPin(url, desc), "addPin($url, $desc)")
-
- assertTrue(poster.deletePin(url), "deletePin($url)")
- }
-
- @Test
- fun testAddPinConfig() {
- val poster = PinboardPoster(localProps)
- if (!isCi) {
- poster.logger.level = Level.FINE
- }
-
- assertTrue(poster.validate(), "validate()")
-
- var config = PinConfig.Builder(url, desc).extended("extra")
-
- assertTrue(poster.addPin(config.build()), "apiToken: ${Constants.ENV_API_TOKEN}")
-
- config = config.tags("foo", "bar")
- assertTrue(poster.addPin(config.build()), "tags(foo,bar)")
-
- config = config.shared(false)
- assertTrue(poster.addPin(config.build()), "shared(false)")
-
- try {
- assertFalse(poster.addPin(config.replace(false).build()))
- } catch (e: IOException) {
- assertTrue(e.message!!.contains("item already exists"))
- }
-
- config = config.description("Yet another test.").replace(true).toRead(true)
- assertTrue(poster.addPin(config.build()), "toRead(true)")
-
- config = config.dt(ZonedDateTime.now())
- assertTrue(poster.addPin(config.build()), "dt(now)")
-
- assertTrue(poster.deletePin(url), "deletePin($url)")
-
- config = config.url(randomUrl())
- assertTrue(poster.addPin(config.build()), "add($url)")
- assertTrue(poster.deletePin(config.url), "delete($url)")
+ assertTrue(poster.addPin(url, desc), "apiToken: ${Constants.ENV_API_TOKEN}")
}
@Test
@@ -126,11 +75,6 @@ class PinboardPosterTest {
}
var poster = PinboardPoster(props)
- if (!isCi) {
- poster.logger.level = Level.FINE
- }
-
- assertTrue(poster.validate(), "validate()")
poster.apiEndPoint = ""
assertFalse(poster.deletePin(url), "apiEndPoint: ")
@@ -138,17 +82,16 @@ class PinboardPosterTest {
poster = PinboardPoster(localProps, Constants.ENV_API_TOKEN)
poster.apiEndPoint = Constants.API_ENDPOINT
- assertTrue(poster.addPin(url, desc), "addPin($url, $desc)")
- assertTrue(poster.deletePin(url), "deletePin($url)")
+ assertTrue(poster.deletePin(url), "apiEndPoint: ${Constants.API_ENDPOINT}")
- assertThrows {
+ expectThrows(IOException::class.java) {
poster.parseMethodResponse("post/delete", "")
}
- assertThrows {
+ expectThrows(IOException::class.java) {
poster.parseMethodResponse("post/delete", "")
}
- assertFalse(poster.deletePin("foo.com"), "deletePin(foo.com)")
+ assertFalse(poster.deletePin("foo.com"), "url: foo.com")
}
}
diff --git a/updatewrappers.sh b/updatewrappers.sh
new file mode 100644
index 0000000..a79d31e
--- /dev/null
+++ b/updatewrappers.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+#
+# Version: 1.0.1
+#
+
+# set the examples directories
+declare -a dirs=(
+ "${PWD##*/}"
+ "samples/java"
+ "samples/kotlin")
+java8=true
+
+###
+
+pwd=$PWD
+cyan=$(tput setaf 6)
+green=$(tput setaf 2)
+red=$(tput setaf 1)
+std=$(tput sgr0)
+
+if [ "$java8" = true ]
+then
+ export JAVA_HOME="$JAVA8_HOME"
+ export PATH="$(cygpath "$JAVA_HOME")/bin:$PATH"
+fi
+
+kVer=$(kobaltw --version | awk '{print substr($2, 1, length($2)-1)}')
+updateWrappers() {
+ curVer="$(gradle --version | awk '/Gradle/ {print $2}')"
+ if [ -d gradle ]; then
+ if [ "$curVer" != "$(./gradlew --version | awk '/Gradle/ {print $2}')" ]; then
+ gradle -q --console=plain wrapper
+ echo -e " $(./gradlew --version | awk '/Gradle/') ${green}UPDATED${std}"
+ else
+ echo -e " Gradle $curVer UP-TO-DATE"
+ fi
+ fi
+ if [ -d kobalt ]; then
+ kw=$(cut -d "=" -f 2 kobalt/wrapper/kobalt-wrapper.properties)
+ if [ "$kw" = "$kVer" ]
+ then
+ echo -e " Kobalt $kw UP-TO-DATE"
+ else
+ echo -e "kobalt.version=$kVer" > kobalt/wrapper/kobalt-wrapper.properties
+ echo -e " Kobalt $kVer ${green}UPDATED${std}"
+ fi
+ fi
+}
+
+echo -e "Updating wrappers..."
+
+for d in "${dirs[@]}"; do
+ if [ -d "$d" ]; then
+ cd "$d" || exit 1
+ fi
+ echo -e " ${cyan}${d}${std}"
+ updateWrappers
+ cd "$pwd"
+done