diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c7f4f3a..75db5d2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,14 +1,181 @@ name: "Build" on: [push, workflow_dispatch] jobs: - build: + test: runs-on: ubuntu-latest + if: github.event_name == 'push' && contains(toJson(github.event.commits), '[ci skip]') == false && contains(toJson(github.event.commits), '[skip ci]') == false steps: - name: "Checkout" uses: actions/checkout@v2 - name: "Setup Java" uses: actions/setup-java@v1 with: - java-version: 8 + java-version: 11 + - name: "Setup Clojure" + uses: DeLaGuardo/setup-clojure@master + with: + cli: "1.10.1.697" + - name: "Clojure Tests" + run: clojure -A:dev:test + - name: "Install Node Dependencies" + run: npm install + - name: "ClojureScript Tests" + run: clojure -A:dev:test-cljs + uberjar: + needs: [test] + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v2 + - name: "Setup Java" + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: "Setup Clojure" + uses: DeLaGuardo/setup-clojure@master + with: + cli: "1.10.1.697" - name: "Clojure Tests" run: clojure -A:dev:test + - name: "Uberjar" + run: clojure -A:uberjar + - name: "Smoke Test" + run: | + java -jar target/dj-data-converter-SNAPSHOT-standalone.jar -h + java -jar target/dj-data-converter-SNAPSHOT-standalone.jar test-resources/collection.nml + java -jar target/dj-data-converter-SNAPSHOT-standalone.jar test-resources/rekordbox.xml + - name: "Upload" + uses: actions/upload-artifact@v2 + with: + name: dj-data-converter-standalone + path: target/dj-data-converter-SNAPSHOT-standalone.jar + native-image-linux: + needs: [uberjar] + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v2 + - name: "Setup GraalVM" + uses: DeLaGuardo/setup-graalvm@3 + with: + graalvm-version: "20.2.0.java11" + - name: "Install GraalVM Native Image Deps" + run: | + sudo apt -y update + sudo apt -y install gcc libc6-dev zlib1g-dev libstdc++-8-dev + - name: "Install GraalVM Native Image" + run: gu install native-image + - name: "Download" + uses: actions/download-artifact@v2 + with: + name: dj-data-converter-standalone + - name: "Native Image" + run: native-image --verbose --no-server --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime --initialize-at-build-time -J-Xmx8g -jar dj-data-converter-SNAPSHOT-standalone.jar -H:Name=dj-data-converter + - name: "Smoke Test" + run: | + chmod +x dj-data-converter + ./dj-data-converter -h + - name: "Package" + run: tar -czvf dj-data-converter-linux.tar.gz dj-data-converter + - name: "Publish" + uses: actions/upload-artifact@v2 + with: + name: dj-data-converter-linux + path: dj-data-converter-linux.tar.gz + native-image-windows: + needs: [uberjar] + runs-on: windows-latest + steps: + - name: "Setup GraalVM" + uses: DeLaGuardo/setup-graalvm@3 + with: + graalvm-version: "20.2.0.java11" + - name: "Install GraalVM Native Image" + run: C:\hostedtoolcache\windows\GraalVM\20.2.0-java11\x64\bin\gu install native-image + - name: "Install Visual C Build Tools Workload for Visual Studio 2017" + run: choco install visualstudio2017-workload-vctools + - name: "Download" + uses: actions/download-artifact@v2 + with: + name: dj-data-converter-standalone + - name: "Native Image" + shell: cmd + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat" + C:\hostedtoolcache\windows\GraalVM\20.2.0-java11\x64\bin\native-image --verbose --no-server --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime --initialize-at-build-time -J-Xmx8g -jar dj-data-converter-SNAPSHOT-standalone.jar -H:Name=dj-data-converter + - name: "Smoke Test" + shell: cmd + run: dj-data-converter.exe -h + - name: "Package" + run: 7z a dj-data-converter-win.zip dj-data-converter.exe + - name: "Publish" + uses: actions/upload-artifact@v2 + with: + name: dj-data-converter-win + path: dj-data-converter-win.zip + native-image-mac: + needs: [uberjar] + runs-on: macos-latest + steps: + - name: "Checkout" + uses: actions/checkout@v2 + - name: "Setup GraalVM" + uses: DeLaGuardo/setup-graalvm@3 + with: + graalvm-version: "20.2.0.java11" + - name: "Install GraalVM Native Image" + run: gu install native-image + - name: "Download" + uses: actions/download-artifact@v2 + with: + name: dj-data-converter-standalone + - name: "Native Image" + run: native-image --verbose --no-server --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime --initialize-at-build-time -J-Xmx8g -jar dj-data-converter-SNAPSHOT-standalone.jar -H:Name=dj-data-converter + - name: "Smoke Test" + run: | + chmod +x dj-data-converter + ./dj-data-converter -h + - name: "Package" + run: tar -czvf dj-data-converter-macos.tar.gz dj-data-converter + - name: "Publish" + uses: actions/upload-artifact@v2 + with: + name: dj-data-converter-macos + path: dj-data-converter-macos.tar.gz + release: + needs: [native-image-linux, native-image-windows, native-image-mac] + runs-on: ubuntu-latest + if: success() && contains(github.ref, 'refs/tags/') + steps: + - name: "Download" + uses: actions/download-artifact@v2 + - name: "Release" + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: true + prerelease: false + - name: "Upload" + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: dj-data-converter-linux/dj-data-converter-linux.tar.gz + asset_name: dj-data-converter-linux.tar.gz + asset_content_type: application/gzip + - name: "Upload" + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: dj-data-converter-win/dj-data-converter-win.zip + asset_name: dj-data-converter-win.zip + asset_content_type: application/zip + - name: "Upload" + uses: actions/upload-release-asset@v1 + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: dj-data-converter-macos/dj-data-converter-macos.tar.gz + asset_name: dj-data-converter-macos.tar.gz + asset_content_type: application/gzip diff --git a/.gitignore b/.gitignore index 5677d82..c37da21 100644 --- a/.gitignore +++ b/.gitignore @@ -10,9 +10,11 @@ pom.xml.asc .cljs_node_repl package-lock.json node_modules -/pkg/ /out/ /cljs-test-runner-out/ .nrepl-port +.calva/ +.clj-kondo/ +/pkg/ /*.xml /*.nml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed39d7..92890ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support the case where an entry has a tempo, but no cues (Traktor to Rekordbox) - Support disabling the "Store Beatmarker as Hotcue" Traktor setting +## 0.5.0 (2020-11-03) +### Changed +- Migrated from JavaScript/NodeJS runtime to Java/GraalVM runtime, in order to fix [#33](https://github.com/digital-dj-tools/dj-data-converter/issues/33) and improve performance generally + ## 0.4.1 (2020-02-04) ### Fixed - Allow DateAdded blank string for Rekordbox tracks [#27](https://github.com/digital-dj-tools/dj-data-converter/issues/27) diff --git a/README.md b/README.md index 177a320..d28891d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# dj-data-converter [![Build Status](https://dev.azure.com/digital-dj-tools/dj-data-converter/_apis/build/status/digital-dj-tools.dj-data-converter?branchName=master)](https://dev.azure.com/digital-dj-tools/dj-data-converter/_build/latest?definitionId=3&branchName=master) +# dj-data-converter [![Build](https://github.com/digital-dj-tools/dj-data-converter/workflows/Build/badge.svg)](https://github.com/digital-dj-tools/dj-data-converter/actions?query=workflow%3ABuild) A command-line app for converting data files to and from different DJ software formats, such as [Traktor](https://www.native-instruments.com/en/products/traktor/dj-software/traktor-pro-3/), [Rekordbox](https://rekordbox.com/en/) and [Serato DJ](https://serato.com/dj). diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 7374c43..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,113 +0,0 @@ - -trigger: - branches: - include: - - refs/heads/* - - refs/tags/* -jobs: -- job: Build - pool: - vmImage: ubuntu-latest - steps: - - script: | - curl -O https://download.clojure.org/install/linux-install-1.10.0.411.sh - chmod +x linux-install-1.10.0.411.sh - sudo ./linux-install-1.10.0.411.sh - displayName: Install Clojure - - script: npm install - displayName: Install Node Dependencies - - script: clojure -Adev:test-cljs - displayName: ClojureScript Tests - - script: clojure -Adev:profile-cljs - displayName: ClojureScript Profiling - - script: | - clojure -A:dev:compile-cljs - npm run build - zip -j pkg/dj-data-converter-win.zip pkg/dj-data-converter-win.exe - chmod +x pkg/dj-data-converter-macos - tar -czvf pkg/dj-data-converter-macos.tar.gz -C pkg dj-data-converter-macos - chmod +x pkg/dj-data-converter-linux - tar -czvf pkg/dj-data-converter-linux.tar.gz -C pkg dj-data-converter-linux - displayName: Package - - task: CopyFiles@2 - inputs: - sourceFolder: pkg - contents: '**' - targetFolder: $(Build.ArtifactStagingDirectory) - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: $(Build.ArtifactStagingDirectory) - artifactName: dj-data-converter - publishLocation: Container -- job: Test_Windows - dependsOn: Build - pool: - vmImage: windows-latest - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - downloadType: single - artifactName: dj-data-converter - downloadPath: $(System.DefaultWorkingDirectory) - - script: dj-data-converter\dj-data-converter-win.exe -h - displayName: Smoke Test -- job: Test_Mac - dependsOn: Build - pool: - vmImage: macOS-latest - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - downloadType: single - artifactName: dj-data-converter - downloadPath: $(System.DefaultWorkingDirectory) - - script: | - chmod +x dj-data-converter/dj-data-converter-macos - dj-data-converter/dj-data-converter-macos -h - displayName: Smoke Test -- job: Test_Linux - dependsOn: Build - pool: - vmImage: ubuntu-latest - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - downloadType: single - artifactName: dj-data-converter - downloadPath: $(System.DefaultWorkingDirectory) - - script: | - chmod +x dj-data-converter/dj-data-converter-linux - dj-data-converter/dj-data-converter-linux -h - displayName: Smoke Test -- job: Release - dependsOn: - - Build - - Test_Windows - - Test_Mac - condition: and(succeeded(), contains(variables['Build.SourceBranch'], 'refs/tags/')) - pool: - vmImage: ubuntu-16.04 - steps: - - task: DownloadBuildArtifacts@0 - inputs: - buildType: current - downloadType: single - artifactName: dj-data-converter - downloadPath: $(System.DefaultWorkingDirectory) - - task: GithubRelease@0 - inputs: - gitHubConnection: digital-dj-tools-bot - repositoryName: digital-dj-tools/dj-data-converter - action: create - target: $(Build.SourceVersion) - tagSource: manual - tag: $(Build.SourceBranchName) - title: $(Build.SourceBranchName) - assets: | - dj-data-converter/*.zip - dj-data-converter/*.tar.gz - isDraft: true - addChangeLog: false \ No newline at end of file diff --git a/compile-opts.edn b/compile-opts.edn index 6c23c73..f617f3a 100644 --- a/compile-opts.edn +++ b/compile-opts.edn @@ -1,4 +1,5 @@ -{:output-to "out/cli.js" +{:output-dir "out" + :output-to "out/cli.js" :target :nodejs :optimizations :simple :source-map "out/cli.js.map"} \ No newline at end of file diff --git a/deps.edn b/deps.edn index 7d9f780..86d5c1c 100644 --- a/deps.edn +++ b/deps.edn @@ -1,24 +1,22 @@ {:paths ["src"] :deps - {org.clojure/clojure {:mvn/version "1.10.1"} - org.clojure/clojurescript {:mvn/version "1.10.520"} + {org.clojure/clojure {:mvn/version "1.10.2-alpha2"} + org.clojure/clojurescript {:mvn/version "1.10.773"} camel-snake-kebab {:mvn/version "0.4.0"} - cljc.java-time {:mvn/version "0.1.6"} + cljc.java-time {:mvn/version "0.1.11"} cljs-node-io {:mvn/version "1.1.2"} com.taoensso/tufte {:mvn/version "2.1.0"} digital-dj-tools/utils {:git/url "https://github.com/digital-dj-tools/utils.git" :sha "a6e97edb71bdba724779c5118811a3cc56d6c877"} digital-dj-tools/mp3-parser {:git/url "https://github.com/digital-dj-tools/mp3-parser.git" - :sha "515c4838dc0b1eadebe64ec5f0a9ed827cfed54c"} + :sha "207bd9f95b260659e050c20de90b7cbbf4376314"} + lambdaisland/uri {:mvn/version "1.4.54"} org.clojure/data.xml {:mvn/version "0.2.0-alpha6"} org.clojure/data.zip {:mvn/version "0.1.3"} org.clojure/tools.cli {:mvn/version "0.4.2"} - metosin/spec-tools {:mvn/version "0.9.3"} - com.cemerick/url {:mvn/version "0.1.1" :exclusions [com.cemerick/clojurescript.test]} - tick {:mvn/version "0.4.19-alpha" - :exclusions [cljsjs/js-joda - cljsjs/js-joda-timezone - cljsjs/js-joda-locale-en-us]}} + metosin/spec-tools {:mvn/version "0.10.0"} + tick {:git/url "https://github.com/juxt/tick.git" + :sha "85aece71140a8a7372fb73f3dfad7cf87cdef9ab"}} :aliases {:dev {:extra-paths ["test"] :extra-deps {net.mikera/core.matrix {:mvn/version "0.62.0"} org.clojure/test.check {:mvn/version "0.10.0"} @@ -32,6 +30,24 @@ :sha "cb96e80f6f3d3b307c59cbeb49bb0dcb3a2a780b"}} :main-opts ["-m" "cognitect.test-runner" "-i" ":profile"]} + :uberjar {:extra-deps {luchiniatwork/cambada {:git/url "https://github.com/xfthhxk/cambada.git" + :sha "c8a01477c856fc28c53f34aa3f268f8eaf683869"}} + :main-opts ["-m" "cambada.uberjar" + "-m" "converter.cli" + "--app-artifact-id" "dj-data-converter" + "--app-version" "SNAPSHOT"]} + :native-image {:extra-deps {luchiniatwork/cambada {:git/url "https://github.com/xfthhxk/cambada.git" + :sha "c8a01477c856fc28c53f34aa3f268f8eaf683869"}} + :main-opts ["-m" "cambada.native-image" + "-m" "converter.cli" + "--graalvm-opt" + "-verbose" + "--graalvm-opt" + "-allow-incomplete-classpath" + "--graalvm-opt" + "-report-unsupported-elements-at-runtime" + "--graalvm-opt" + "J-Xmx8g"]} :test-cljs {:extra-deps {olical/cljs-test-runner {:mvn/version "3.7.0"}} :main-opts ["-m" "cljs-test-runner.main" "-e" ":profile"]} diff --git a/src/converter/app.cljc b/src/converter/app.cljc old mode 100644 new mode 100755 index 4d79170..b8a5505 --- a/src/converter/app.cljc +++ b/src/converter/app.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.app (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/cli.cljc b/src/converter/cli.cljc old mode 100644 new mode 100755 index 1480f78..275aa18 --- a/src/converter/cli.cljc +++ b/src/converter/cli.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.cli (:require #?(:cljs [cljs.nodejs :as nodejs]) diff --git a/src/converter/config.cljc b/src/converter/config.cljc old mode 100644 new mode 100755 index f8e3445..793235d --- a/src/converter/config.cljc +++ b/src/converter/config.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.config (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/error.cljc b/src/converter/error.cljc old mode 100644 new mode 100755 index 2f18aa6..d5ee2f2 --- a/src/converter/error.cljc +++ b/src/converter/error.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.error (:require #?(:cljs [cljs-node-io.core :as io :refer [spit]]) diff --git a/src/converter/js_joda.cljs b/src/converter/js_joda.cljs deleted file mode 100644 index c0966fd..0000000 --- a/src/converter/js_joda.cljs +++ /dev/null @@ -1,5 +0,0 @@ -(ns converter.js-joda) - -(set! js/JSJoda (js/require "js-joda")) - -(set! js/JSJodaLocale (js/require "@js-joda/locale_en-us")) \ No newline at end of file diff --git a/src/converter/offset.cljc b/src/converter/offset.cljc old mode 100644 new mode 100755 index cd4f663..e2097c3 --- a/src/converter/offset.cljc +++ b/src/converter/offset.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.offset (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/progress.cljc b/src/converter/progress.cljc old mode 100644 new mode 100755 index a4b5cd0..b507a08 --- a/src/converter/progress.cljc +++ b/src/converter/progress.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.progress) (defn dots-println diff --git a/src/converter/rekordbox/core.cljc b/src/converter/rekordbox/core.cljc old mode 100644 new mode 100755 index 6f5deb1..2952aea --- a/src/converter/rekordbox/core.cljc +++ b/src/converter/rekordbox/core.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.rekordbox.core (:require [camel-snake-kebab.core :as csk] diff --git a/src/converter/rekordbox/position_mark.cljc b/src/converter/rekordbox/position_mark.cljc old mode 100644 new mode 100755 index 79e2222..af4057e --- a/src/converter/rekordbox/position_mark.cljc +++ b/src/converter/rekordbox/position_mark.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.rekordbox.position-mark (:require [camel-snake-kebab.core :as csk] diff --git a/src/converter/rekordbox/tempo.cljc b/src/converter/rekordbox/tempo.cljc old mode 100644 new mode 100755 index 2ac6443..73579dd --- a/src/converter/rekordbox/tempo.cljc +++ b/src/converter/rekordbox/tempo.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.rekordbox.tempo (:require [camel-snake-kebab.core :as csk] diff --git a/src/converter/spec.cljc b/src/converter/spec.cljc old mode 100644 new mode 100755 index 3921cab..11bdc10 --- a/src/converter/spec.cljc +++ b/src/converter/spec.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.spec (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/str.cljc b/src/converter/str.cljc old mode 100644 new mode 100755 index e79629f..1baf8b0 --- a/src/converter/str.cljc +++ b/src/converter/str.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.str (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/time.cljc b/src/converter/time.cljc old mode 100644 new mode 100755 index 407fb5f..9fa2b2f --- a/src/converter/time.cljc +++ b/src/converter/time.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.time (:require [cljc.java-time.local-date :as jtld] @@ -5,10 +6,10 @@ #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) #?(:clj [clojure.spec.gen.alpha :as gen] :cljs [cljs.spec.gen.alpha :as gen]) [clojure.string :as string] - #?(:cljs [converter.js-joda]) [spec-tools.core :as st] [tick.alpha.api :as t] [tick.format :as tf] + #?(:cljs [tick.locale-en-us]) #?(:cljs [java.time :refer [Instant Clock LocalDate]])) #?(:clj (:import diff --git a/src/converter/traktor/album.cljc b/src/converter/traktor/album.cljc old mode 100644 new mode 100755 index 451b1a0..15e534b --- a/src/converter/traktor/album.cljc +++ b/src/converter/traktor/album.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.traktor.album (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]))) diff --git a/src/converter/traktor/core.cljc b/src/converter/traktor/core.cljc old mode 100644 new mode 100755 index a7be224..379572b --- a/src/converter/traktor/core.cljc +++ b/src/converter/traktor/core.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.traktor.core (:require [clojure.data.zip.xml :as zx] diff --git a/src/converter/traktor/cue.cljc b/src/converter/traktor/cue.cljc old mode 100644 new mode 100755 index d545a3f..e9da448 --- a/src/converter/traktor/cue.cljc +++ b/src/converter/traktor/cue.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.traktor.cue (:require [clojure.data.zip.xml :as zx] diff --git a/src/converter/traktor/location.cljc b/src/converter/traktor/location.cljc old mode 100644 new mode 100755 index 77a86bc..5799546 --- a/src/converter/traktor/location.cljc +++ b/src/converter/traktor/location.cljc @@ -1,6 +1,6 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.traktor.location (:require - [cemerick.url :refer [url url-encode url-decode]] [clojure.data.zip.xml :as zx] #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) [clojure.string :as string] @@ -9,6 +9,8 @@ [converter.str :as str] [converter.traktor.nml :as nml] [converter.url :as url] + [lambdaisland.uri :as uri] + [lambdaisland.uri.normalize :as urin] [spec-tools.data-spec :as std])) (def location @@ -41,8 +43,8 @@ file (last paths) volume (if (str/drive-letter? (first paths)) (first paths))] {:tag :LOCATION - :attrs (cond-> {:DIR (nml/nml-dir (map url-decode dirs)) - :FILE (url-decode file)} + :attrs (cond-> {:DIR (nml/nml-dir (map urin/percent-decode dirs)) + :FILE (urin/percent-decode file)} volume (assoc :VOLUME volume))})) (defn location-z-file-is-not-blank? @@ -64,8 +66,9 @@ (let [dir (zx/attr location-z :DIR) file (zx/attr location-z :FILE) volume (zx/attr location-z :VOLUME)] - (apply url (as-> [] $ - (conj $ "file://localhost") - (conj $ (if (str/drive-letter? volume) (str "/" volume) "")) - (reduce conj $ (map url-encode (string/split dir nml/nml-path-sep-regex))) - (conj $ (url-encode file)))))) \ No newline at end of file + ((comp uri/uri (partial string/join "/") (partial remove empty?) flatten) + (as-> [] $ + (conj $ "file://localhost") + (conj $ (if (str/drive-letter? volume) volume "")) + (conj $ (map #(urin/percent-encode % :path) (string/split dir nml/nml-path-sep-regex))) + (conj $ (urin/percent-encode file :path)))))) \ No newline at end of file diff --git a/src/converter/traktor/nml.cljc b/src/converter/traktor/nml.cljc old mode 100644 new mode 100755 index 6f0b109..232f1f1 --- a/src/converter/traktor/nml.cljc +++ b/src/converter/traktor/nml.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.traktor.nml (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/universal/core.cljc b/src/converter/universal/core.cljc old mode 100644 new mode 100755 index 4a07728..cf15d4e --- a/src/converter/universal/core.cljc +++ b/src/converter/universal/core.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.universal.core (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/universal/marker.cljc b/src/converter/universal/marker.cljc old mode 100644 new mode 100755 index 4d5e26e..a26ec7f --- a/src/converter/universal/marker.cljc +++ b/src/converter/universal/marker.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.universal.marker (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/universal/tempo.cljc b/src/converter/universal/tempo.cljc old mode 100644 new mode 100755 index ee30523..aa0e306 --- a/src/converter/universal/tempo.cljc +++ b/src/converter/universal/tempo.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.universal.tempo (:require #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) diff --git a/src/converter/url.cljc b/src/converter/url.cljc old mode 100644 new mode 100755 index eea786b..f7462d8 --- a/src/converter/url.cljc +++ b/src/converter/url.cljc @@ -1,25 +1,24 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.url (:require - [cemerick.url :as url] #?(:clj [clojure.java.io :as io]) [clojure.string :as string] #?(:clj [clojure.spec.alpha :as s] :cljs [cljs.spec.alpha :as s]) #?(:clj [clojure.spec.gen.alpha :as gen] :cljs [cljs.spec.gen.alpha :as gen]) [converter.str :as str] #?(:cljs [file-uri-to-path]) + [lambdaisland.uri :as uri] + [lambdaisland.uri.normalize :as urin] [spec-tools.core :as st])) ; TODO only accept file:// urls -; it is assumed that the string is already url-encoded +; it is assumed that the string is already url encoded (defn string->url [_ str] (if (string? str) (try - ; on cljs/node, cemerick/url seems to be doing url decoding for whitespace (%20), no idea why.. - ; so on cljs, whitespace is url encoded again - #?(:clj (url/url str) - :cljs (-> str url/url (update :path #(string/replace % " " "%20")))) + (uri/uri str) (catch #?(:clj Exception, :cljs js/Error) _ str)) str)) @@ -46,39 +45,38 @@ (string/replace "%2C" ",") (string/replace "%3F" "?")))) -(defn drive->wsl - [url wsl?] - (if wsl? - (url/url url (string/replace (:path url) - #"^/([A-Z]):/" - #(str "/mnt/" (string/lower-case (% 1)) "/"))) - - url)) - (defn url-gen [] - (->> (gen/tuple - ;; base - (gen/elements #{"file://localhost"}) - ;; drive letter (optional) - (gen/one-of [(str/drive-letter-gen) (gen/elements #{""})]) - ;; path - (->> (str/not-blank-string-with-whitespace-gen) - (gen/fmap url/url-encode) - (gen/vector) - (gen/not-empty))) - (gen/fmap - #(apply url/url (flatten %))))) + (gen/fmap (comp uri/uri (partial string/join "/") (partial remove empty?) flatten) + (gen/tuple + (gen/elements #{"file://localhost"}) + (gen/one-of [(str/drive-letter-gen) (gen/elements #{""})]) + (->> (str/not-blank-string-with-whitespace-gen) + (gen/fmap #(urin/percent-encode % :path)) + (gen/vector) + (gen/not-empty))))) (s/def ::url (st/spec (s/and - #(instance? cemerick.url.URL %) - #(= "file" (:protocol %))) + #(instance? lambdaisland.uri.URI %) ; TODO is this really needed? + #(= "file" (:scheme %))) {:type :url :gen #(url-gen)})) (defn file-ext [url] (->> url - :path - (re-find #"\.([^\.]+)$") - second)) \ No newline at end of file + :path + (re-find #"\.([^\.]+)$") + second)) + +(s/fdef drive->wsl + :args (s/cat :url ::url :wsl? boolean?) + :ret ::url) + +(defn drive->wsl + [url wsl?] + (if wsl? + (uri/join url (string/replace (:path url) + #"^/([A-Z]):/" + #(str "/mnt/" (string/lower-case (% 1)) "/"))) + url)) \ No newline at end of file diff --git a/src/converter/xml.cljc b/src/converter/xml.cljc old mode 100644 new mode 100755 index 7db3837..2e76b4f --- a/src/converter/xml.cljc +++ b/src/converter/xml.cljc @@ -1,3 +1,4 @@ +#?(:clj (set! *warn-on-reflection* true)) (ns converter.xml (:require #?(:cljs [converter.xmldom]) diff --git a/test/converter/traktor_test.cljc b/test/converter/traktor_test.cljc index 9b22d7a..298057a 100644 --- a/test/converter/traktor_test.cljc +++ b/test/converter/traktor_test.cljc @@ -10,6 +10,7 @@ [converter.spec :as spec] [converter.traktor.core :as t] [converter.traktor.cue :as tc] + [converter.traktor.location :as tl] [converter.test-utils :as test] [converter.universal.core :as u] [plumula.mimolette.alpha :refer [defspec-test]] @@ -17,12 +18,12 @@ (defspec-test location->url - `t/location->url + `tl/location->url {:opts {:num-tests 100}}) (defspec-test url->location - `t/url->location + `tl/url->location {:opts {:num-tests 100}}) (defspec-test diff --git a/test/converter/url_test.cljc b/test/converter/url_test.cljc new file mode 100644 index 0000000..bb34246 --- /dev/null +++ b/test/converter/url_test.cljc @@ -0,0 +1,9 @@ +(ns converter.url-test + (:require + [converter.url :as url] + [plumula.mimolette.alpha :refer [defspec-test]])) + +(defspec-test + drive->wsl + `url/drive->wsl + {:opts {:num-tests 100}})