diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json deleted file mode 100644 index c810878..0000000 --- a/.config/dotnet-tools.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "fake-cli": { - "version": "5.21.1", - "commands": [ - "fake" - ] - }, - "fsharp.formatting.commandtool": { - "version": "11.2.0", - "commands": [ - "fsdocs" - ] - } - } -} \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3393841..1ac1dbb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,27 +12,23 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: '6.0.x' - - name: Restore local tools - run: dotnet tool restore - name: Build and test - run: dotnet fake build -t runTests + run: dotnet run --project ./build/Build.fsproj runTests build-and-test-windows: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: '6.0.x' - - name: Restore local tools - run: dotnet tool restore - name: Build and test - run: dotnet fake build -t runTests + run: dotnet run --project ./build/Build.fsproj runTests diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index 7e59faf..03af9d0 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -11,21 +11,19 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: '6.0.x' - - name: Restore local tools - run: dotnet tool restore - name: Build and publish - run: dotnet fake build -t publishBinariesWin + run: dotnet run --project ./build/Build.fsproj publishBinariesWin - uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "v0.4.0-win.x64" + automatic_release_tag: "v0.5.0-win.x64" prerelease: false - title: "v0.4.0-win.x64" + title: "v0.5.0-win.x64" files: | src/ArcCommander/config_win/config publish/win-x64/arc.exe @@ -35,21 +33,19 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: '6.0.x' - - name: Restore local tools - run: dotnet tool restore - name: Build and publish - run: dotnet fake build -t publishBinariesLinux + run: dotnet run --project ./build/Build.fsproj publishBinariesLinux - uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "v0.4.0-linux.x64" + automatic_release_tag: "v0.5.0-linux.x64" prerelease: false - title: "v0.4.0-linux.x64" + title: "v0.5.0-linux.x64" files: | src/ArcCommander/config_unix/config publish/linux-x64/arc @@ -59,21 +55,19 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: '6.0.x' - - name: Restore local tools - run: dotnet tool restore - name: Build and publish - run: dotnet fake build -t publishBinariesMac + run: dotnet run --project ./build/Build.fsproj publishBinariesMac - uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "v0.4.0-osx.x64" + automatic_release_tag: "v0.5.0-osx.x64" prerelease: false - title: "v0.4.0-osx.x64" + title: "v0.5.0-osx.x64" files: | src/ArcCommander/config_unix/config publish/osx-x64/arc \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5e00ef6..6db300d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ [Dd]ebug/ [Rr]elease/ x64/ -build/ +# build/ [Bb]in/ [Oo]bj/ diff --git a/ArcCommander.sln b/ArcCommander.sln index 03dbf55..db399b9 100644 --- a/ArcCommander.sln +++ b/ArcCommander.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32825.248 MinimumVisualStudioVersion = 15.0.26124.0 Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ArcCommander", "src\ArcCommander\ArcCommander.fsproj", "{E482262C-A2BF-44E9-BCD0-A7E2E80F419C}" EndProject @@ -13,9 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{655069DF-7 .gitignore = .gitignore .github\workflows\build-and-test.yml = .github\workflows\build-and-test.yml build.cmd = build.cmd - build.fsx = build.fsx build.sh = build.sh - .config\dotnet-tools.json = .config\dotnet-tools.json global.json = global.json README.md = README.md .github\workflows\release-github.yml = .github\workflows\release-github.yml @@ -28,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".devcontainer", ".devcontai .devcontainer\Dockerfile = .devcontainer\Dockerfile EndProjectSection EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Build", "build\Build.fsproj", "{44736484-8325-4C62-8BA5-3091FB02FAE7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +62,18 @@ Global {618F5887-509A-4C7A-8536-6CCA51A8F85B}.Release|x64.Build.0 = Release|Any CPU {618F5887-509A-4C7A-8536-6CCA51A8F85B}.Release|x86.ActiveCfg = Release|Any CPU {618F5887-509A-4C7A-8536-6CCA51A8F85B}.Release|x86.Build.0 = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|x64.ActiveCfg = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|x64.Build.0 = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Debug|x86.Build.0 = Debug|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|Any CPU.Build.0 = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|x64.ActiveCfg = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|x64.Build.0 = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|x86.ActiveCfg = Release|Any CPU + {44736484-8325-4C62-8BA5-3091FB02FAE7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index c3e89b5..0000000 --- a/Directory.Build.props +++ /dev/null @@ -1,13 +0,0 @@ - - - https://github.com/nfdi4plants/arcCommander/blob/master/LICENSE - https://nfdi4plants.github.io/arcCommander/ - https://github.com/nfdi4plants/arcCommander/ - https://fsharp.org - https://github.com/nfdi4plants/arcCommander/blob/master/License.txt - https://github.com/nfdi4plants/arcCommander/blob/master/RELEASE_NOTES.md - fixed-left - true - default - - \ No newline at end of file diff --git a/README.md b/README.md index ddc7841..3b710dd 100644 --- a/README.md +++ b/README.md @@ -1,202 +1,11 @@ -# ArcCommander +# ARC Commander -ArcCommander is a command line tool to create, manage and share your ARCs. +ARC Commander is a command line tool to create, manage and share your ARCs. -## Install and start +## Install and use -- [Windows](#windows) -- [Linux](#linux) -- [MacOS](#macos) +Please visit the [ARC Commander Manual](https://nfdi4plants.org/nfdi4plants.knowledgebase/docs/ArcCommanderManual/index.html) in the DataPLANT Knowledge Base to find guides on ARC Commander installation and use. -Head over to [Releases](https://github.com/nfdi4plants/arcCommander/releases). Download the newest release for the OS you use. +## Develop and contribute -Start the ArcCommander with the respective OS's command-line shell. -A global config file will be created the first time you use the ArcCommander in the following folder: -- Windows: `:\Users\\AppData\Roaming\DataPLANT\ArcCommander\` -- Unix: `~/.config/DataPLANT/ArcCommander/` - -We strongly recommend to read the in-depth guide to the ArcCommander in this repository's [Wiki](https://github.com/nfdi4plants/arcCommander/wiki)! - -### Windows - -1. In Windows Explorer, head over to the folder where you downloaded the ArcCommander, e.g. -![image](https://user-images.githubusercontent.com/47781170/118627514-13e63f00-b7cc-11eb-95cb-1bf74a355cde.png) -2. You can move the .exe to a desired folder, e.g. to your personal folder -3. Add the folder with the ArcCommander to your PATH: - - Open the Start Menu, type in `path` and click on _Edit the system environment variables_ - ![image](https://user-images.githubusercontent.com/47781170/119674721-b8a3f480-be3c-11eb-9982-e3c0fa191f05.png) - - Click on _Environment Variables..._, click on _Path_ and on _Edit..._ in the tab _User variables for _, click on _New_ and type in the full path to your folder as seen in the example below: - ![image](https://user-images.githubusercontent.com/47781170/119674652-a9bd4200-be3c-11eb-81f8-72f1198842ef.png) - - This allows you to start the ArcCommander from any folder - - **Please make sure that you do not have any blank spaces in your path** -4. Navigate to a folder in which you want to initialize an ARC -5. Open the Command Prompt (CMD) via typing in `cmd` in the folder address, press Enter -![image](https://user-images.githubusercontent.com/47781170/119680874-dd4e9b00-be41-11eb-8faf-ed699c827395.png) -6. Run the ArcCommander from the CMD by executing `arc` - -### Linux - -1. Download the latest ArcCommander release - - ```bash - wget https://github.com/nfdi4plants/arcCommander/releases/download/v0.3.4-linux.x64/arc - ``` - -1. Make it executable - - ```bash - chmod u+x arc - ``` - -1. Move to suitable place (e.g. in your home directory or to `/home/bin/` to make it accessible for all users) - - ```bash - if ! [ -d "$HOME/bin" ]; then mkdir "$HOME/bin"; fi # If it does not exist, create a folder `bin` in your home directory. - mv arc $HOME/bin/ # move executable to that folder - ``` - -1. You might have to start a fresh terminal or `source ~/.profile` - -1. Test that ArcCommander is properly installed - - ```bash - arc --version # check the current version - ``` - -You should see the following or similar message: - -> Start processing parameterless command. -> Start Arc Version -> v0.3.4 -> Done processing command. - -### MacOS - -1. Open a Terminal (Applications -> Utilities -> Terminal) -2. Copy/paste the following commands into your terminal and execute them to (a) download the latest ArcCommander release, (b) change permissions to make the arcCommander executable and (c) move the arcCommander program to a location from where it is executable via the terminal: - - ```bash - - curl -L https://github.com/nfdi4plants/arcCommander/releases/download/v0.3.4-osx.x64/arc > arc - chmod u+x ./arc - mv ./arc /usr/local/bin/ - ``` - -3. Run arcCommander from the terminal by executing: - - ```bash - arc - ``` - -4. MacOS security note: On first execution, MacOS will not allow arc to be run. Instead it opens a pop-up: - - > "arc" cannot be opened because it is from an unidentified developer - -5. Open the Security Panel in system Preferences (Applications -> System Preferences -> "Security & Privacy") or by executing the following command in your terminal: - - ```bash - open "x-apple.systempreferences:com.apple.preference.security" - ``` - - In the "General" tab click the bottom-right button "Allow Anyway" right next to - > arc was blocked from use because it is not from an identified developer. - -6. Head back to the terminal and execute `arc` again. Another pop-up will ask you to confirm by clicking "Open". - -7. Check that arc is properly installed by executing - - ```bash - arc --version - ``` - -You should see the following or similar message: - -> Start processing parameterless command. -> Start Arc Version -> v0.3.4 -> Done processing command. - ---- - -## Develop - -The following part addresses all who want to contribute to the ArcCommander. -If you only want to simply use the ArcCommander, head over to [Install and start](https://github.com/nfdi4plants/arcCommander#install-and-start). - -### Prerequisites - -- .NET SDK >= 3.1.00 (should roll forward to .net 6 if you are using that) -- To test the generated cli tool you will need the .NET 3.1 runtime. - -### Build - -Check the [build.fsx file](https://github.com/nfdi4plants/arcCommander/blob/developer/build.fsx) to take a look at the build targets. Here are some examples: - -#### via dotnet cli - -- run `dotnet tool restore` once to restore local tools needed in the buildchain - -- run `dotnet fake build -t ` to run the buildchain of `` - - Examples: - - - `dotnet fake build` run the default buildchain (clean artifacts, build projects, copy binaries to /bin) - - - `dotnet fake build -t runTests` (clean artifacts, build projects, copy binaries to /bin, **run unit tests**) - - - `dotnet fake build -t publishBinaries` (clean artifacts, build projects, copy binaries to /bin, **publish project as single-file executable** depending on `` which can be either `Win`, `Mac`, or `Linux`) - -#### using the shell scripts - -```shell -# Windows - -# Build only -./build.cmd - -# Full release buildchain: build, test, pack, build the docs, push a git tag, publish the nuget package, release the docs -./build.cmd -t release - -# The same for prerelease versions: -./build.cmd -t prerelease - -# Publish buildchain: build, publish for the respective OS -./publishBinariesWin.cmd -./publishBinariesMac.cmd -./publishBinariesLnx.cmd - - -# Linux/mac - -# Build only -build.sh - -# Full release buildchain: build, test, pack, build the docs, push a git tag, publsih the nuget package, release the docs -build.sh -t release - -# The same for prerelease versions: -build.sh -t prerelease - -``` - -### Update Release Notes - -Every developer with writing rights shall update the Release Notes after every PR merge: - -#### via dotnet cli - -- run `dotnet tool restore` once to restore local tools needed in the buildchain (if not done already) - -- run `dotnet fake build -t releaseNotes` to update the Release Notes with commits not added yet **to the CURRENT version release** - -- run `dotnet fake build -t releaseNotes semver:` to update the Release Notes with commits not added yet **to a NEW version release**; the new version depends on the ` 1.0.0), `minor` for an increase of the minor number (e.g. 0.0.0 -> 0.1.0), `patch` for an increase of the patch number (e.g. 0.0.0 -> 0.0.1) - -### Release on github - -To release the newest versions of the ArcCommander binaries on github, just `push` the newest version to the `main` branch. You must `update the release notes` as described above prior to this, as otherwise an old release may be overwritten by the new one. - -Release workflow is based on https://github.com/marketplace/actions/automatic-releases - -#### testing the binary - -After running the default build target, binaries of the arcCommander tool will lie in ./bin/ArcCommander. To run the binary, either use the `ArcCommander.exe` file on windows or `dotnet ArcCommander.dll` on linux. +If you want to contribute to the ARC Commander development, please visit the [ARC Commander Development Docs](https://nfdi4plants.github.io/arcCommander-docs/). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9b29e01..1a51635 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,11 +1,52 @@ -### 0.4.0+5d16b16 (Released 2022-12-14) +### 0.5.0+59f219b (Released 2023-4-12) * Additions: - * latest commit #5d16b16 + * [[#ea33a5f](https://github.com/nfdi4plants/arcCommander/commit/ea33a5fbc688f880f0ae733843d8c40a43bea74d)] Merge pull request #174 from Freymaurer/developer + * [[#fc698ce](https://github.com/nfdi4plants/arcCommander/commit/fc698ce40f00468fc0fbd8c55c9f7ab73630e436)] Move GitHub workflows to meta folder + * [[#87ab386](https://github.com/nfdi4plants/arcCommander/commit/87ab38689163d4a3fed3e3abde161c2d8c683e08)] Add Giraffe package and Server-related static files to .fsproj + * [[#4116fe3](https://github.com/nfdi4plants/arcCommander/commit/4116fe3f665da3694a4b7019811ef750a1d55247)] Add ArcAPIHandler functions + * [[#913eb3c](https://github.com/nfdi4plants/arcCommander/commit/913eb3c7ac5f263c9d6dbfe5f6707cbbc6617b34)] Add Server.fs with `arc server` functions, WebRoot and ApiDocs to project + * [[#c4471da](https://github.com/nfdi4plants/arcCommander/commit/c4471da4e5e5023d46dc31c5d7e49217de462038)] Add Argu commands & args for Server functionality + * [[#d0e3a09](https://github.com/nfdi4plants/arcCommander/commit/d0e3a09a387a4cac50889b2fc7cf9fd1e66baf21)] Merge pull request #175 from nfdi4plants/ArcServer + * [[#85a6c89](https://github.com/nfdi4plants/arcCommander/commit/85a6c8998eb15df850ba94513eea2fb712c230d9)] Update FAKE in .proj file & .NET SDK in global.json + * [[#91eb7a6](https://github.com/nfdi4plants/arcCommander/commit/91eb7a6d8fcdf39bfb6efe9640f8b95d606879cc)] move loggind to arcIO + * [[#6c051b1](https://github.com/nfdi4plants/arcCommander/commit/6c051b188cf93e3da98be39d7b4fa8120c896585)] add arc convert command + * [[#e7fa3f2](https://github.com/nfdi4plants/arcCommander/commit/e7fa3f27aee4b284962d024f06749e650e5d16ed)] use update functionality defined in arcIO.Net + * [[#2c5796d](https://github.com/nfdi4plants/arcCommander/commit/2c5796deec340ea9d0b335e302ce0b71ea4376f0)] replace study list with arcIO.NET function + * [[#ca663e1](https://github.com/nfdi4plants/arcCommander/commit/ca663e106ceb2121ef4e91645ca942fb5d04cd77)] update test action to .net 7 + * [[#f39eea7](https://github.com/nfdi4plants/arcCommander/commit/f39eea770752d335663973a22ca89427882deca1)] update Fake versions + * [[#9350650](https://github.com/nfdi4plants/arcCommander/commit/93506507c768c5c7770ae639b9dbce300ede9aa1)] add json to convert command + * [[#73c970d](https://github.com/nfdi4plants/arcCommander/commit/73c970d5df856d3939e8a68f6e7c5d49de306623)] set .net sdk version of github action to 6.0 + * [[#4a30252](https://github.com/nfdi4plants/arcCommander/commit/4a30252ee6ff44f0c266bfe749b8514a2bb2db62)] loosen .NET version constraints in global.json + * [[#59f219b](https://github.com/nfdi4plants/arcCommander/commit/59f219bc0791e3fad5563b66618d07e1b8d6066d)] Merge pull request #181 from nfdi4plants/arcIONetMigration +* Bugfixes: + * [[#857b2ef](https://github.com/nfdi4plants/arcCommander/commit/857b2efbc451b45dd247bdb43493be1eb669f5f2)] Fix DirectorySeparatorChar in tests for linux :bug: + * [[#810f791](https://github.com/nfdi4plants/arcCommander/commit/810f791b942c068837041a6aaab7239cfd124c0a)] fix empty study being left when adding assay + * [[#c7a84e9](https://github.com/nfdi4plants/arcCommander/commit/c7a84e9a92a8548bc0a242c576575e0391ae3bcd)] fix study list + +### 0.4.0+c769c38 (Released 2023-1-3) +* Additions: + * [[#35bdf43](https://github.com/nfdi4plants/arcCommander/commit/35bdf4327b19a84e27f3794b9fe3b5fef55d8990)] Add Version.fs to arccommander project. + * [[#ae1c773](https://github.com/nfdi4plants/arcCommander/commit/ae1c7733487464dd6f074e60dd517d15fd589ddc)] Clean up open modules in build project. + * [[#7951930](https://github.com/nfdi4plants/arcCommander/commit/79519301f218c7795f81de9fa8fe174208b698dc)] bump to 0.4.0 + * [[#c8257c5](https://github.com/nfdi4plants/arcCommander/commit/c8257c5128738ef23711e977887242614a4743b0)] Clean up README.md :books: + * [[#f89eb28](https://github.com/nfdi4plants/arcCommander/commit/f89eb2820477f35f2dfab0f8532f599bfcf3acde)] rename default gitignore filename in source folder + * [[#c37540f](https://github.com/nfdi4plants/arcCommander/commit/c37540fc0e180fe59e41b5a40ad433a68ea3ead3)] replace default gitignore with os-specific rules + * [[#e404f65](https://github.com/nfdi4plants/arcCommander/commit/e404f65301401b71b094815b053106d5ff74218b)] throw warning when character length of file name arguments exceed 31 + * [[#fd75cc8](https://github.com/nfdi4plants/arcCommander/commit/fd75cc870760cc45431ba73528fc3354b9ee8488)] add filename attribute info to argument query + * [[#0601c1f](https://github.com/nfdi4plants/arcCommander/commit/0601c1f2af3a7565e8429132c95f2bb966303e19)] move readme parts and link to new online resources + * [[#14ded34](https://github.com/nfdi4plants/arcCommander/commit/14ded3442e943f415e36de3abb4857a2d93a6e63)] Add build project :tada: + * [[#e782d3d](https://github.com/nfdi4plants/arcCommander/commit/e782d3da476537ab9bb5177a3f816b98981b8ac7)] Update github workflows + * [[#cd97d52](https://github.com/nfdi4plants/arcCommander/commit/cd97d5283c4d024cdc0fb37739e75ae78134c00f)] Update global.json + * [[#435a80a](https://github.com/nfdi4plants/arcCommander/commit/435a80a9f074a65ac63d51262254e32699e6ef21)] Clean up solution * [[#555a52e](https://github.com/nfdi4plants/arcCommander/commit/555a52e30c2888f493160666207754d1e99936cd)] Add FileNameAttribute to AssayEditArgs * [[#b3abd03](https://github.com/nfdi4plants/arcCommander/commit/b3abd03166a67fafd4ececd0fbc61154c8f35abe)] add direct access token storing functionality * [[#e2aeed5](https://github.com/nfdi4plants/arcCommander/commit/e2aeed5a5800c23fe6ab6435ee75d71c80781ed7)] add nolfs flag to arc get - +* Deletions: + * [[#5f3345b](https://github.com/nfdi4plants/arcCommander/commit/5f3345b77feacc3e77bd64ad7357d35b2287909a)] Remove deprecated files :fire: + * [[#60479ad](https://github.com/nfdi4plants/arcCommander/commit/60479ada0a4f414fde1935b3c8ccec67dfba74a6)] Update executables * Bugfixes: + * [[#c769c38](https://github.com/nfdi4plants/arcCommander/commit/c769c386a83d0ed08b3cd7a5c7f2dd890a174897)] Fix typos in github workflows :bug: + * [[#d330e51](https://github.com/nfdi4plants/arcCommander/commit/d330e51ce0feefa56e95ab016160432ead981d9f)] Fix "build and tests" issues :bug: * [[#cca00ce](https://github.com/nfdi4plants/arcCommander/commit/cca00cec140154c1610b7a2417e1510f7a4a1acc)] Fix critical error not catching forbidden chars * [[#476c97d](https://github.com/nfdi4plants/arcCommander/commit/476c97d1a4fad9791578db443d18c5a1f445963c)] fix git lfs tracking @@ -153,69 +194,59 @@ * Deletions: * [[#91a3dee](https://github.com/nfdi4plants/arcCommander/commit/91a3dee82367ed06152c5c7833265579873367f8)] Delete deprecated assembly source file :fire: -#### 0.1.4 - Wednesday, January 26, 2022 +### 0.1.4 (Released 2023-1-3) * Additions: * latest commit #8f34df30 * ArcCommander is now able to call external tools. :sparkles: -#### 0.1.3 - Tuesday, January 11, 2022 - -- Person functions for assay commands now available. -- `arc i show` now available. -- ArcCommander now logs every action. - -#### 0.1.2 - Tuesday, November 2, 2021 - -- Publish tasks now available in build script. -- CLI scripts for ARC templates. -- Unit tests for `person update`. -- Raised .NET 5.0 target. -- Now it is possible to convert an ARC to a JSON object via JSON export. -- Global config file now gets created automatically (with default parameters). - -#### 0.1.1 - Thursday, May 20, 2021 - -- Configurable Git LFS threshold. -- Issue templates available now. - -#### 0.1.0 - Wednesday, April 28, 2021 - -- First release! :tada: -- New synchronize command. -- New Git commands and API. -- Now packed as dotnet tool. - -#### 0.0.7-alpha - Thursday, February 11, 2021, - -- Unit tests for Investigation, Assay, Study. -- Updated build chain. -- ISA-XLSX moved to ISA.NET: https://github.com/nfdi4plants/ISADotNet - -#### 0.0.6-alpha - Tuesday, January 19, 2021 - -- Removed FSharpSpreadsheetML to its own repository: https://github.com/CSBiology/FSharpSpreadsheetML - -#### 0.0.5-alpha - Wednesday, January 6, 2021 - -- Global and local config file and configuration backbone added. -- SpreadsheetML refactored. -- ISA-XLSX and ISA-XLSX.IO unit tests added. - -#### 0.0.4-alpha - Monday, November 9, 2020 - -- Improved CLIArgs. -- Assay subcommands. -- Investigation subcommands. -- Sheet functions added. - -#### 0.0.3-alpha - Wednesday, October 21, 2020 - -- Added ISA-XLSX project. - -#### 0.0.2-alpha - Monday, October 12, 2020 - -- Added ArcCommander project. - -#### 0.0.1-alpha - Saturday, September 5, 2020 +### 0.1.3 (Released 2023-1-3) + * - Person functions for assay commands now available. + * - `arc i show` now available. + * - ArcCommander now logs every action. + +### 0.1.2 (Released 2023-1-3) + * - Publish tasks now available in build script. + * - CLI scripts for ARC templates. + * - Unit tests for `person update`. + * - Raised .NET 5.0 target. + * - Now it is possible to convert an ARC to a JSON object via JSON export. + * - Global config file now gets created automatically (with default parameters). + +### 0.1.1 (Released 2023-1-3) + * - Configurable Git LFS threshold. + * - Issue templates available now. + +### 0.1.0 (Released 2023-1-3) + * - First release! :tada: + * - New synchronize command. + * - New Git commands and API. + * - Now packed as dotnet tool. + +### 0.0.7-alpha (Released 2023-1-3) + * - Unit tests for Investigation, Assay, Study. + * - Updated build chain. + * - ISA-XLSX moved to ISA.NET: https://github.com/nfdi4plants/ISADotNet + +### 0.0.6-alpha (Released 2023-1-3) + * - Removed FSharpSpreadsheetML to its own repository: https://github.com/CSBiology/FSharpSpreadsheetML + +### 0.0.5-alpha (Released 2023-1-3) + * - Global and local config file and configuration backbone added. + * - SpreadsheetML refactored. + * - ISA-XLSX and ISA-XLSX.IO unit tests added. + +### 0.0.4-alpha (Released 2023-1-3) + * - Improved CLIArgs. + * - Assay subcommands. + * - Investigation subcommands. + * - Sheet functions added. + +### 0.0.3-alpha (Released 2023-1-3) + * - Added ISA-XLSX project. + +### 0.0.2-alpha (Released 2023-1-3) + * - Added ArcCommander project. + +### 0.0.1-alpha (Released 2023-1-3) + * Created repository.** -**Created repository.** diff --git a/build.cmd b/build.cmd index f1a5d82..33614ea 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,4 @@ -dotnet tool restore -dotnet fake build %* \ No newline at end of file +@echo off +cls + +dotnet run --project ./build/Build.fsproj %* \ No newline at end of file diff --git a/build.fsx b/build.fsx deleted file mode 100644 index c7b9763..0000000 --- a/build.fsx +++ /dev/null @@ -1,481 +0,0 @@ -#r "paket: -nuget BlackFox.Fake.BuildTask -nuget Fake.Core.Target -nuget Fake.Core.Process -nuget Fake.Core.ReleaseNotes -nuget Fake.IO.FileSystem -nuget Fake.DotNet.Cli -nuget Fake.DotNet.MSBuild -nuget Fake.DotNet.AssemblyInfoFile -nuget Fake.DotNet.Paket -nuget Fake.DotNet.FSFormatting -nuget Fake.DotNet.Fsi -nuget Fake.DotNet.NuGet -nuget Fake.Api.Github -nuget Fake.DotNet.Testing.Expecto -nuget Fake.Extensions.Release -nuget Fake.IO.Zip -nuget Fake.Tools.Git //" - -#if !FAKE -#load "./.fake/build.fsx/intellisense.fsx" -#r "netstandard" // Temp fix for https://github.com/dotnet/fsharp/issues/5216 -#endif - -open BlackFox.Fake -open System.IO -open Fake.Core -open Fake.DotNet -open Fake.IO -open Fake.IO.FileSystemOperators -open Fake.IO.Globbing.Operators -open Fake.Tools - -[] -/// user interaction prompts for critical build tasks where you may want to interrupt when you see wrong inputs. -module MessagePrompts = - - let prompt (msg:string) = - System.Console.Write(msg) - System.Console.ReadLine().Trim() - |> function | "" -> None | s -> Some s - |> Option.map (fun s -> s.Replace ("\"","\\\"")) - - let rec promptYesNo msg = - match prompt (sprintf "%s [Yn]: " msg) with - | Some "Y" | Some "y" -> true - | Some "N" | Some "n" -> false - | _ -> System.Console.WriteLine("Sorry, invalid answer"); promptYesNo msg - - let releaseMsg = """This will stage all uncommitted changes, push them to the origin and bump the release version to the latest number in the RELEASE_NOTES.md file. - Do you want to continue?""" - - let releaseDocsMsg = """This will push the docs to gh-pages. Remember building the docs prior to this. Do you want to continue?""" - -/// Executes a dotnet command in the given working directory -let runDotNet cmd workingDir = - let result = - DotNet.exec (DotNet.Options.withWorkingDirectory workingDir) cmd "" - if result.ExitCode <> 0 then failwithf "'dotnet %s' failed in %s" cmd workingDir - -/// Metadata about the project -module ProjectInfo = - - let project = "ArcCommander" - - let testProject = "tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj" - - let summary = "ArcCommander is a command line tool to create, manage and share your ARCs." - - let solutionFile = "ArcCommander.sln" - - let configuration = "Release" - - // Git configuration (used for publishing documentation in gh-pages branch) - // The profile where the project is posted - let gitOwner = "nfdi4plants" - let gitHome = sprintf "%s/%s" "https://github.com" gitOwner - - let gitName = "arcCommander" - - let website = "/arcCommander" - - let pkgDir = "pkg" - - let publishDir = "publish" - - let release = ReleaseNotes.load "RELEASE_NOTES.md" - - let projectRepo = "https://github.com/nfdi4plants/arcCommander" - - let stableVersion = SemVer.parse release.NugetVersion - - let stableVersionTag = (sprintf "%i.%i.%i" stableVersion.Major stableVersion.Minor stableVersion.Patch ) - - let mutable prereleaseSuffix = "" - - let mutable prereleaseTag = "" - - let mutable isPrerelease = false - - -/// Barebones, minimal build tasks -module BasicTasks = - - open ProjectInfo - - let setPrereleaseTag = BuildTask.create "SetPrereleaseTag" [] { - printfn "Please enter pre-release package suffix" - let suffix = System.Console.ReadLine() - prereleaseSuffix <- suffix - prereleaseTag <- (sprintf "%s-%s" release.NugetVersion suffix) - isPrerelease <- true - } - - let clean = BuildTask.create "Clean" [] { - !! "src/**/bin" - ++ "src/**/obj" - ++ "pkg" - ++ "bin" - |> Shell.cleanDirs - } - - let cleanTestResults = - BuildTask.create "cleanTestResults" [] { - Shell.cleanDirs (!! "tests/**/**/TestResult") - } - - let build = BuildTask.create "Build" [clean] { - solutionFile - |> DotNet.build id - } - - let copyBinaries = BuildTask.create "CopyBinaries" [clean; build] { - let targets = - !! "src/**/*.??proj" - -- "src/**/*.shproj" - |> Seq.map (fun f -> ((Path.getDirectory f) "bin" configuration, "bin" (Path.GetFileNameWithoutExtension f))) - for i in targets do printfn "%A" i - targets - |> Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true)) - } - -/// Test executing build tasks -module TestTasks = - - open ProjectInfo - open BasicTasks - - let runTests = BuildTask.create "RunTests" [clean; cleanTestResults; build; copyBinaries] { - let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () - Fake.DotNet.DotNet.test(fun testParams -> - { - testParams with - Logger = Some "console;verbosity=detailed" - Configuration = DotNet.BuildConfiguration.fromString configuration - NoBuild = true - } - ) testProject - } - -/// Package creation -module PackageTasks = - - open ProjectInfo - - open BasicTasks - open TestTasks - - let pack = BuildTask.create "Pack" [clean; build; runTests; copyBinaries] { - if promptYesNo (sprintf "creating stable package with version %s OK?" stableVersionTag ) - then - !! "src/**/*.*proj" - |> Seq.iter (Fake.DotNet.DotNet.pack (fun p -> - let msBuildParams = - {p.MSBuildParams with - Properties = ([ - "Version",stableVersionTag - "PackageReleaseNotes", (release.Notes |> String.concat "\r\n") - ] @ p.MSBuildParams.Properties) - } - { - p with - MSBuildParams = msBuildParams - OutputPath = Some pkgDir - NoBuild = true - Configuration = DotNet.BuildConfiguration.fromString configuration - } - )) - else failwith "aborted" - } - - let packPrerelease = BuildTask.create "PackPrerelease" [setPrereleaseTag; clean; build; runTests; copyBinaries] { - if promptYesNo (sprintf "package tag will be %s OK?" prereleaseTag ) - then - !! "src/**/*.*proj" - //-- "src/**/Plotly.NET.Interactive.fsproj" - |> Seq.iter (Fake.DotNet.DotNet.pack (fun p -> - let msBuildParams = - {p.MSBuildParams with - Properties = ([ - "Version", prereleaseTag - "PackageReleaseNotes", (release.Notes |> String.toLines ) - ] @ p.MSBuildParams.Properties) - } - { - p with - VersionSuffix = Some prereleaseSuffix - OutputPath = Some pkgDir - NoBuild = true - Configuration = DotNet.BuildConfiguration.fromString configuration - } - )) - else - failwith "aborted" - } - - let publishBinariesWin = BuildTask.create "PublishBinariesWin" [clean.IfNeeded; build.IfNeeded] { - let outputPath = sprintf "%s/win-x64" publishDir - solutionFile - |> DotNet.publish (fun p -> - let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () - { - p with - Runtime = Some "win-x64" - Configuration = DotNet.BuildConfiguration.fromString configuration - OutputPath = Some outputPath - MSBuildParams = { - standardParams with - Properties = [ - "Version", stableVersionTag - "Platform", "x64" - "PublishSingleFile", "true" - ] - }; - } - ) - printfn "Beware that assemblyName differs from projectName!" - } - - let publishBinariesLinux = BuildTask.create "PublishBinariesLinux" [clean.IfNeeded; build.IfNeeded] { - let outputPath = sprintf "%s/linux-x64" publishDir - solutionFile - |> DotNet.publish (fun p -> - let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () - { - p with - Runtime = Some "linux-x64" - Configuration = DotNet.BuildConfiguration.fromString configuration - OutputPath = Some outputPath - MSBuildParams = { - standardParams with - Properties = [ - "Version", stableVersionTag - "Platform", "x64" - "PublishSingleFile", "true" - ] - } - } - ) - printfn "Beware that assemblyName differs from projectName!" - } - - let publishBinariesMac = BuildTask.create "PublishBinariesMac" [clean.IfNeeded; build.IfNeeded] { - let outputPath = sprintf "%s/osx-x64" publishDir - solutionFile - |> DotNet.publish (fun p -> - let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () - { - p with - Runtime = Some "osx-x64" - Configuration = DotNet.BuildConfiguration.fromString configuration - OutputPath = Some outputPath - MSBuildParams = { - standardParams with - Properties = [ - "Version", stableVersionTag - "Platform", "x64" - "PublishSingleFile", "true" - ] - } - } - ) - printfn "Beware that assemblyName differs from projectName!" - } - - let publishBinariesAll = BuildTask.createEmpty "PublishBinariesAll" [clean; build; publishBinariesWin; publishBinariesLinux; publishBinariesMac] - -module ToolTasks = - - open ProjectInfo - open BasicTasks - open TestTasks - open PackageTasks - - let installPackagedTool = BuildTask.create "InstallPackagedTool" [packPrerelease] { - Directory.ensure "tests/tool-tests" - runDotNet "new tool-manifest --force" "tests/tool-tests" - runDotNet (sprintf "tool install --add-source ../../%s ArcCommander --version %s" pkgDir prereleaseTag) "tests/tool-tests" - } - - let testPackagedTool = BuildTask.create "TestPackagedTool" [installPackagedTool] { - runDotNet "ArcCommander --help" "tests/tool-tests" - } - -/// Build tasks for documentation setup and development -module DocumentationTasks = - - open ProjectInfo - - open BasicTasks - - let buildDocs = BuildTask.create "BuildDocs" [build; copyBinaries] { - printfn "building docs with stable version %s" stableVersionTag - runDotNet - (sprintf "fsdocs build --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" stableVersionTag) - "./" - } - - let buildDocsPrerelease = BuildTask.create "BuildDocsPrerelease" [setPrereleaseTag; build; copyBinaries] { - printfn "building docs with prerelease version %s" prereleaseTag - runDotNet - (sprintf "fsdocs build --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" prereleaseTag) - "./" - } - - let watchDocs = BuildTask.create "WatchDocs" [build; copyBinaries] { - printfn "watching docs with stable version %s" stableVersionTag - runDotNet - (sprintf "fsdocs watch --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" stableVersionTag) - "./" - } - - let watchDocsPrerelease = BuildTask.create "WatchDocsPrerelease" [setPrereleaseTag; build; copyBinaries] { - printfn "watching docs with prerelease version %s" prereleaseTag - runDotNet - (sprintf "fsdocs watch --eval --clean --property Configuration=Release --parameters fsdocs-package-version %s" prereleaseTag) - "./" - } - -/// Buildtasks that release stuff, e.g. packages, git tags, documentation, etc. -module ReleaseTasks = - - open ProjectInfo - - open BasicTasks - open TestTasks - open PackageTasks - open DocumentationTasks - - let createTag = BuildTask.create "CreateTag" [clean; build; copyBinaries; runTests; pack] { - if promptYesNo (sprintf "tagging branch with %s OK?" stableVersionTag ) then - Git.Branches.tag "" stableVersionTag - Git.Branches.pushTag "" projectRepo stableVersionTag - else - failwith "aborted" - } - - let createPrereleaseTag = BuildTask.create "CreatePrereleaseTag" [setPrereleaseTag; clean; build; copyBinaries; runTests; packPrerelease] { - if promptYesNo (sprintf "tagging branch with %s OK?" prereleaseTag ) then - Git.Branches.tag "" prereleaseTag - Git.Branches.pushTag "" projectRepo prereleaseTag - else - failwith "aborted" - } - - - let publishNuget = BuildTask.create "PublishNuget" [clean; build; copyBinaries; runTests; pack] { - let targets = (!! (sprintf "%s/*.*pkg" pkgDir )) - for target in targets do printfn "%A" target - let msg = sprintf "release package with version %s?" stableVersionTag - if promptYesNo msg then - let source = "https://api.nuget.org/v3/index.json" - let apikey = Environment.environVar "NUGET_KEY" - for artifact in targets do - let result = DotNet.exec id "nuget" (sprintf "push -s %s -k %s %s --skip-duplicate" source apikey artifact) - if not result.OK then failwith "failed to push packages" - else failwith "aborted" - } - - let publishNugetPrerelease = BuildTask.create "PublishNugetPrerelease" [clean; build; copyBinaries; runTests; packPrerelease] { - let targets = (!! (sprintf "%s/*.*pkg" pkgDir )) - for target in targets do printfn "%A" target - let msg = sprintf "release package with version %s?" prereleaseTag - if promptYesNo msg then - let source = "https://api.nuget.org/v3/index.json" - let apikey = Environment.environVar "NUGET_KEY" - for artifact in targets do - let result = DotNet.exec id "nuget" (sprintf "push -s %s -k %s %s --skip-duplicate" source apikey artifact) - if not result.OK then failwith "failed to push packages" - else failwith "aborted" - } - - let releaseDocs = BuildTask.create "ReleaseDocs" [buildDocs] { - let msg = sprintf "release docs for version %s?" stableVersionTag - if promptYesNo msg then - Shell.cleanDir "temp" - Git.CommandHelper.runSimpleGitCommand "." (sprintf "clone %s temp/gh-pages --depth 1 -b gh-pages" projectRepo) |> ignore - Shell.copyRecursive "output" "temp/gh-pages" true |> printfn "%A" - Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" "add ." |> printfn "%s" - let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" stableVersionTag - Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" cmd |> printfn "%s" - Git.Branches.push "temp/gh-pages" - else failwith "aborted" - } - - let prereleaseDocs = BuildTask.create "PrereleaseDocs" [buildDocsPrerelease] { - let msg = sprintf "release docs for version %s?" prereleaseTag - if promptYesNo msg then - Shell.cleanDir "temp" - Git.CommandHelper.runSimpleGitCommand "." (sprintf "clone %s temp/gh-pages --depth 1 -b gh-pages" projectRepo) |> ignore - Shell.copyRecursive "output" "temp/gh-pages" true |> printfn "%A" - Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" "add ." |> printfn "%s" - let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" prereleaseTag - Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" cmd |> printfn "%s" - Git.Branches.push "temp/gh-pages" - else failwith "aborted" - } - -module ReleaseNoteTasks = - - open Fake.Extensions.Release - - let updateVersionOfReleaseWorkflow (stableVersionTag) = - printfn "Start updating release-github workflow to version %s" stableVersionTag - let filePath = Path.Combine(__SOURCE_DIRECTORY__,".github/workflows/release-github.yml") - let s = File.readAsString filePath - let lastVersion = System.Text.RegularExpressions.Regex.Match(s,@"v\d+.\d+.\d+").Value - s.Replace(lastVersion,$"v{stableVersionTag}") - |> File.writeString false filePath - - let createAssemblyVersion = BuildTask.create "createvfs" [] { - AssemblyVersion.create ProjectInfo.gitName - } - - let updateReleaseNotes = BuildTask.createFn "ReleaseNotes" [] (fun config -> - Release.exists() - - Release.update(ProjectInfo.gitOwner, ProjectInfo.gitName, config) - - let release = ReleaseNotes.load "RELEASE_NOTES.md" - - let stableVersion = SemVer.parse release.NugetVersion - - let stableVersionTag = (sprintf "%i.%i.%i" stableVersion.Major stableVersion.Minor stableVersion.Patch ) - - updateVersionOfReleaseWorkflow (stableVersionTag) - ) - - let githubDraft = BuildTask.createFn "GithubDraft" [] (fun config -> - - let body = "We are ready to go for the first release!" - - Github.draft( - ProjectInfo.gitOwner, - ProjectInfo.gitName, - (Some body), - None, - config - ) - ) - -open BasicTasks -open TestTasks -open PackageTasks -open DocumentationTasks -open ReleaseTasks - -/// Full release of nuget package, git tag, and documentation for the stable version. -let _release = - BuildTask.createEmpty - "Release" - [clean; build; copyBinaries; runTests; pack; buildDocs; createTag; publishNuget; releaseDocs] - -/// Full release of nuget package, git tag, and documentation for the prerelease version. -let _preRelease = - BuildTask.createEmpty - "PreRelease" - [setPrereleaseTag; clean; build; copyBinaries; runTests; packPrerelease; buildDocsPrerelease; createPrereleaseTag; publishNugetPrerelease; prereleaseDocs] - -// run copyBinaries by default -BuildTask.runOrDefaultWithArguments copyBinaries \ No newline at end of file diff --git a/build.fsx.lock b/build.fsx.lock deleted file mode 100644 index de4c306..0000000 --- a/build.fsx.lock +++ /dev/null @@ -1,745 +0,0 @@ -STORAGE: NONE -RESTRICTION: || (== net6.0) (== netstandard2.0) -NUGET - remote: https://api.nuget.org/v3/index.json - BlackFox.Fake.BuildTask (0.1.3) - Fake.Core.Target (>= 5.1) - FSharp.Core (>= 4.3.4) - BlackFox.VsWhere (1.1) - FSharp.Core (>= 4.2.3) - Microsoft.Win32.Registry (>= 4.7) - Fake.Api.Github (5.22) - FSharp.Core (>= 6.0) - Octokit (>= 0.50) - Fake.Core.CommandLineParsing (5.22) - FParsec (>= 1.1.1) - FSharp.Core (>= 6.0) - Fake.Core.Context (5.22) - FSharp.Core (>= 6.0) - Fake.Core.Environment (5.22) - FSharp.Core (>= 6.0) - Fake.Core.FakeVar (5.22) - Fake.Core.Context (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Core.Process (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.FakeVar (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - System.Collections.Immutable (>= 5.0) - Fake.Core.ReleaseNotes (5.22) - Fake.Core.SemVer (>= 5.22) - Fake.Core.String (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Core.SemVer (5.22) - FSharp.Core (>= 6.0) - Fake.Core.String (5.22) - FSharp.Core (>= 6.0) - Fake.Core.Target (5.22) - Fake.Core.CommandLineParsing (>= 5.22) - Fake.Core.Context (>= 5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.FakeVar (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - FSharp.Control.Reactive (>= 5.0.2) - FSharp.Core (>= 6.0) - Fake.Core.Tasks (5.22) - Fake.Core.Trace (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Core.Trace (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.FakeVar (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Core.Xml (5.22) - Fake.Core.String (>= 5.22) - FSharp.Core (>= 6.0) - Fake.DotNet.AssemblyInfoFile (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - Fake.DotNet.Cli (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.DotNet.MSBuild (>= 5.22) - Fake.DotNet.NuGet (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - Mono.Posix.NETStandard (>= 1.0) - Newtonsoft.Json (>= 13.0.1) - Fake.DotNet.FSFormatting (5.22) - Fake.Core.Process (>= 5.22) - Fake.DotNet.Cli (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - Fake.DotNet.Fsi (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.DotNet.MSBuild (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - Fake.Tools.Git (>= 5.22) - FSharp.Compiler.Service (>= 37.0) - FSharp.Core (>= 6.0) - Fake.DotNet.MSBuild (5.22) - BlackFox.VsWhere (>= 1.1) - Fake.Core.Environment (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - MSBuild.StructuredLogger (>= 2.1.545) - Fake.DotNet.NuGet (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.SemVer (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Tasks (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.Core.Xml (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - Fake.Net.Http (>= 5.22) - FSharp.Core (>= 6.0) - Newtonsoft.Json (>= 13.0.1) - NuGet.Protocol (>= 5.11) - Fake.DotNet.Paket (5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.DotNet.Cli (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - Fake.DotNet.Testing.Expecto (5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - Fake.Testing.Common (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Extensions.Release (0.2) - Fake.Api.Github (>= 5.20.3) - Fake.Core.ReleaseNotes (>= 5.20.3) - Fake.Core.Target (>= 5.20.3) - Fake.DotNet.AssemblyInfoFile (>= 5.20.3) - Fake.IO.FileSystem (>= 5.20.3) - Fake.IO.Zip (>= 5.20.3) - Fake.Tools.Git (>= 5.20.3) - FSharp.Core (>= 5.0) - Fake.IO.FileSystem (5.22) - Fake.Core.String (>= 5.22) - FSharp.Core (>= 6.0) - Fake.IO.Zip (5.22) - Fake.Core.String (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Net.Http (5.22) - Fake.Core.Trace (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Testing.Common (5.22) - Fake.Core.Trace (>= 5.22) - FSharp.Core (>= 6.0) - Fake.Tools.Git (5.22) - Fake.Core.Environment (>= 5.22) - Fake.Core.Process (>= 5.22) - Fake.Core.SemVer (>= 5.22) - Fake.Core.String (>= 5.22) - Fake.Core.Trace (>= 5.22) - Fake.IO.FileSystem (>= 5.22) - FSharp.Core (>= 6.0) - FParsec (1.1.1) - FSharp.Core (>= 4.3.4) - FSharp.Compiler.Service (41.0.2) - FSharp.Core (6.0.2) - Microsoft.Build.Framework (>= 17.0.0-preview-21515-03) - Microsoft.Build.Tasks.Core (>= 17.0.0-preview-21515-03) - Microsoft.Build.Utilities.Core (>= 17.0.0-preview-21515-03) - System.Buffers (>= 4.5.1) - System.Collections.Immutable (>= 5.0) - System.Diagnostics.Process (>= 4.3) - System.Diagnostics.TraceSource (>= 4.3) - System.Linq.Expressions (>= 4.3) - System.Linq.Queryable (>= 4.3) - System.Memory (>= 4.5.4) - System.Net.Requests (>= 4.3) - System.Net.Security (>= 4.3.1) - System.Reflection.Emit (>= 4.3) - System.Reflection.Metadata (>= 5.0) - System.Reflection.TypeExtensions (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.CompilerServices.Unsafe (>= 5.0) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Loader (>= 4.3) - System.Security.Claims (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Principal (>= 4.3) - System.Threading.Tasks.Parallel (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - FSharp.Control.Reactive (5.0.2) - FSharp.Core (>= 4.7.2) - System.Reactive (>= 5.0) - FSharp.Core (6.0.2) - Microsoft.Build (17.0) - Microsoft.Build.Framework (>= 17.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.NET.StringTools (>= 1.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.Win32.Registry (>= 4.3) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) - System.Collections.Immutable (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Configuration.ConfigurationManager (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Reflection.Metadata (>= 1.6) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) - System.Security.Principal.Windows (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) - System.Text.Encoding.CodePages (>= 4.0.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) - System.Text.Json (>= 5.0.2) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Threading.Tasks.Dataflow (>= 4.9) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.Build.Framework (17.0) - System.Security.Permissions (>= 4.7) - Microsoft.Build.Tasks.Core (17.0) - Microsoft.Build.Framework (>= 17.0) - Microsoft.Build.Utilities.Core (>= 17.0) - Microsoft.NET.StringTools (>= 1.0) - Microsoft.Win32.Registry (>= 4.3) - System.CodeDom (>= 4.4) - System.Collections.Immutable (>= 5.0) - System.Reflection.Metadata (>= 1.6) - System.Resources.Extensions (>= 4.6) - System.Security.Cryptography.Pkcs (>= 4.7) - System.Security.Cryptography.Xml (>= 4.7) - System.Security.Permissions (>= 4.7) - System.Threading.Tasks.Dataflow (>= 4.9) - Microsoft.Build.Utilities.Core (17.0) - Microsoft.Build.Framework (>= 17.0) - Microsoft.NET.StringTools (>= 1.0) - Microsoft.Win32.Registry (>= 4.3) - System.Collections.Immutable (>= 5.0) - System.Configuration.ConfigurationManager (>= 4.7) - System.Security.Permissions (>= 4.7) - System.Text.Encoding.CodePages (>= 4.0.1) - Microsoft.NET.StringTools (1.0) - System.Memory (>= 4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 5.0) - Microsoft.NETCore.Platforms (6.0.1) - Microsoft.NETCore.Targets (5.0) - Microsoft.Win32.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - Microsoft.Win32.Registry (5.0) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) - System.Security.AccessControl (>= 5.0) - System.Security.Principal.Windows (>= 5.0) - Microsoft.Win32.SystemEvents (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Mono.Posix.NETStandard (1.0) - MSBuild.StructuredLogger (2.1.630) - Microsoft.Build (>= 16.10) - Microsoft.Build.Framework (>= 16.10) - Microsoft.Build.Tasks.Core (>= 16.10) - Microsoft.Build.Utilities.Core (>= 16.10) - Newtonsoft.Json (13.0.1) - NuGet.Common (6.1) - NuGet.Frameworks (>= 6.1) - NuGet.Configuration (6.1) - NuGet.Common (>= 6.1) - System.Security.Cryptography.ProtectedData (>= 4.4) - NuGet.Frameworks (6.1) - NuGet.Packaging (6.1) - Newtonsoft.Json (>= 13.0.1) - NuGet.Configuration (>= 6.1) - NuGet.Versioning (>= 6.1) - System.Security.Cryptography.Cng (>= 5.0) - System.Security.Cryptography.Pkcs (>= 5.0) - NuGet.Protocol (6.1) - NuGet.Packaging (>= 6.1) - NuGet.Versioning (6.1) - Octokit (0.50) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Net.Http (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Net.Security (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - System.Buffers (4.5.1) - System.CodeDom (6.0) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Concurrent (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Collections.Immutable (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Configuration.ConfigurationManager (6.0) - System.Security.Cryptography.ProtectedData (>= 6.0) - System.Security.Permissions (>= 6.0) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.DiagnosticSource (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< net5.0)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Diagnostics.Process (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - Microsoft.Win32.Registry (>= 4.3) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encoding.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Diagnostics.TraceSource (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Diagnostics.Tracing (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Drawing.Common (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Microsoft.Win32.SystemEvents (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - System.Formats.Asn1 (6.0) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Globalization.Calendars (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Runtime (>= 4.3) - System.Globalization.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Linq.Expressions (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Linq (>= 4.3) - System.ObjectModel (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Emit (>= 4.3) - System.Reflection.Emit.ILGeneration (>= 4.3) - System.Reflection.Emit.Lightweight (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Reflection.TypeExtensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Linq.Queryable (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Linq (>= 4.3) - System.Linq.Expressions (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Memory (4.5.4) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Net.Http (4.3.4) - Microsoft.NETCore.Platforms (>= 1.1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.DiagnosticSource (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Primitives (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (>= 4.3) - System.Net.Requests (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Net.Http (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Net.WebHeaderCollection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Security (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Security (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Claims (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Security.Principal (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Net.WebHeaderCollection (4.3) - System.Collections (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Numerics.Vectors (4.5) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (== netstandard2.0) - System.ObjectModel (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Reactive (5.0) - System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Emit (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) - System.Reflection.Emit.ILGeneration (4.7) - System.Reflection.Emit.Lightweight (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< portable-net45+wp8)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) - System.Reflection.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Metadata (6.0) - System.Collections.Immutable (>= 6.0) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Reflection.TypeExtensions (4.7) - System.Resources.Extensions (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime.CompilerServices.Unsafe (6.0) - System.Runtime.Extensions (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - System.Runtime (>= 4.3.1) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices.WindowsRuntime (4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Runtime (>= 4.3) - System.Runtime.Loader (4.3) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Numerics (4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Security.AccessControl (6.0) - System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) - System.Security.Claims (4.3) - System.Collections (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Security.Principal (>= 4.3) - System.Security.Cryptography.Algorithms (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.Cng (5.0) - System.Formats.Asn1 (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - System.Security.Cryptography.Csp (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (5.0) - System.Formats.Asn1 (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) - System.Security.Cryptography.Pkcs (6.0) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) - System.Formats.Asn1 (>= 6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) - System.Security.Cryptography.Primitives (4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Security.Cryptography.ProtectedData (6.0) - System.Security.Cryptography.X509Certificates (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Calendars (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Cng (>= 4.3) - System.Security.Cryptography.Csp (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Xml (6.0) - System.Memory (>= 4.5.4) - restriction: == netstandard2.0 - System.Security.AccessControl (>= 6.0) - System.Security.Cryptography.Pkcs (>= 6.0) - System.Security.Permissions (6.0) - System.Security.AccessControl (>= 6.0) - System.Windows.Extensions (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - System.Security.Principal (4.3) - System.Runtime (>= 4.3) - System.Security.Principal.Windows (5.0) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding.CodePages (6.0) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Encoding.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encodings.Web (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Json (6.0.2) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Encodings.Web (>= 6.0) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Threading.Tasks.Dataflow (6.0) - System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (== netstandard2.0) - System.Threading.Tasks.Parallel (4.3) - System.Collections.Concurrent (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (4.3) - System.Runtime (>= 4.3) - System.Threading.ThreadPool (4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Windows.Extensions (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - System.Drawing.Common (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) diff --git a/build.sh b/build.sh index 2cbbce7..ccd770c 100644 --- a/build.sh +++ b/build.sh @@ -3,5 +3,4 @@ set -eu set -o pipefail -dotnet tool restore -dotnet fake build "$@" \ No newline at end of file +dotnet run --project ./build/Build.fsproj %* \ No newline at end of file diff --git a/build/BasicTasks.fs b/build/BasicTasks.fs new file mode 100644 index 0000000..4409fd4 --- /dev/null +++ b/build/BasicTasks.fs @@ -0,0 +1,47 @@ +module BasicTasks + +open System.IO +open Fake.IO +open Fake.DotNet +open Fake.IO.Globbing.Operators +open BlackFox.Fake + +open ProjectInfo + + +let setPrereleaseTag = BuildTask.create "SetPrereleaseTag" [] { + printfn "Please enter pre-release package suffix" + let suffix = System.Console.ReadLine() + prereleaseSuffix <- suffix + prereleaseTag <- (sprintf "%s-%s" release.NugetVersion suffix) + isPrerelease <- true +} + +let clean = BuildTask.create "Clean" [] { + !! "src/**/bin" + ++ "src/**/obj" + ++ "pkg" + ++ "bin" + |> Shell.cleanDirs +} + +let cleanTestResults = BuildTask.create "cleanTestResults" [] { + Shell.cleanDirs (!! "tests/**/**/TestResult") +} + +let build = BuildTask.create "Build" [clean] { + solutionFile + |> DotNet.build id +} + +open Fake.IO.FileSystemOperators + +let copyBinaries = BuildTask.create "CopyBinaries" [clean; build] { + let targets = + !! "src/**/*.??proj" + -- "src/**/*.shproj" + |> Seq.map (fun f -> ((Path.getDirectory f) "bin" configuration, "bin" (Path.GetFileNameWithoutExtension f))) + for i in targets do printfn "%A" i + targets + |> Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true)) +} \ No newline at end of file diff --git a/build/Build.fs b/build/Build.fs new file mode 100644 index 0000000..0846230 --- /dev/null +++ b/build/Build.fs @@ -0,0 +1,30 @@ +open BlackFox.Fake +open Helpers + +open BasicTasks +open TestTasks +open PackageTasks +open ReleaseTasks + +initializeContext() + +// Could also use existing build project template found here: https://github.com/kMutagene/BuildProject + +// Make targets accessible +ReleaseNoteTasks.updateReleaseNotes |> ignore +DockerTasks.dockerPublish |> ignore + +/// Full release of nuget package, git tag, and documentation for the stable version. +let _release = + BuildTask.createEmpty + "Release" + [clean; build; copyBinaries; runTests; pack; createTag; publishNuget] + +/// Full release of nuget package, git tag, and documentation for the prerelease version. +let _preRelease = + BuildTask.createEmpty + "PreRelease" + [setPrereleaseTag; clean; build; copyBinaries; runTests; packPrerelease; createPrereleaseTag; publishNugetPrerelease] + +[] +let main args = runOrDefault args \ No newline at end of file diff --git a/build/Build.fsproj b/build/Build.fsproj new file mode 100644 index 0000000..8ce5d26 --- /dev/null +++ b/build/Build.fsproj @@ -0,0 +1,37 @@ + + + + + Exe + net6.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/DockerTasks.fs b/build/DockerTasks.fs new file mode 100644 index 0000000..79aa376 --- /dev/null +++ b/build/DockerTasks.fs @@ -0,0 +1,52 @@ +module DockerTasks + +open BlackFox.Fake +open Fake.Core +open Helpers + +open Fake.Extensions.Release + +let dockerImageName = "freymaurer/swate" +let dockerContainerName = "swate" + +// Change target to github-packages +// https://docs.github.com/en/actions/publishing-packages/publishing-docker-images +let dockerPublish = BuildTask.create "docker-publish" [] { + let releaseNotesPath = "RELEASE_NOTES.md" + let port = "5000" + + ReleaseNotes.ensure() + let newRelease = ReleaseNotes.load releaseNotesPath + + let dockerCreateImage() = run docker $"build -t {dockerContainerName} -f build/Dockerfile.publish . " "" + let dockerTestImage() = run docker $"run -it -p {port}:{port} {dockerContainerName}" "" + let dockerTagImage() = + run docker $"tag {dockerContainerName}:latest {dockerImageName}:{newRelease.SemVer.Major}.{newRelease.SemVer.Minor}.{newRelease.SemVer.Patch}" "" + run docker $"tag {dockerContainerName}:latest {dockerImageName}:latest" "" + let dockerPushImage() = + run docker $"push {dockerImageName}:{newRelease.SemVer.Major}.{newRelease.SemVer.Minor}.{newRelease.SemVer.Patch}" "" + run docker $"push {dockerImageName}:latest" "" + let dockerPublish() = + Trace.trace $"Tagging image with :latest and :{newRelease.SemVer.Major}.{newRelease.SemVer.Minor}.{newRelease.SemVer.Patch}" + dockerTagImage() + Trace.trace $"Pushing image to dockerhub with :latest and :{newRelease.SemVer.Major}.{newRelease.SemVer.Minor}.{newRelease.SemVer.Patch}" + dockerPushImage() + // Check if next SemVer is correct + if promptYesNo $"Is version {newRelease.SemVer.Major}.{newRelease.SemVer.Minor}.{newRelease.SemVer.Patch} correct?" then + Trace.trace "Perfect! Starting with docker publish" + Trace.trace "Creating image" + dockerCreateImage() + // Check if user wants to test image + if promptYesNo "Want to test the image?" then + Trace.trace $"Your app on port {port} will open on localhost:{port}." + dockerTestImage() + // Check if user wants the image published + if promptYesNo $"Is the image working as intended?" then + dockerPublish() + else + Trace.traceErrorfn "Cancel docker-publish" + else + dockerPublish() + else + Trace.traceErrorfn "Please update your SemVer Version in %s" releaseNotesPath +} \ No newline at end of file diff --git a/build/Dockerfile.publish b/build/Dockerfile.publish new file mode 100644 index 0000000..e7aa2ad --- /dev/null +++ b/build/Dockerfile.publish @@ -0,0 +1,14 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 as build + +WORKDIR /workspace +COPY . . +RUN dotnet tool restore +RUN dotnet publish -c Release -o out + + +FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine + +COPY --from=build /workspace/out /app +WORKDIR /app +EXPOSE 5000 +ENTRYPOINT [ "dotnet", "arc.dll", "server" ] \ No newline at end of file diff --git a/build/Dockerfile.publish.dockerignore b/build/Dockerfile.publish.dockerignore new file mode 100644 index 0000000..c9a30cc --- /dev/null +++ b/build/Dockerfile.publish.dockerignore @@ -0,0 +1,17 @@ +.fable/ +*.fs.js +*.fs.js.map +.fake/ +.farmer/ +.idea/ +.ionide/ +.vs/ +deploy/ +obj/ +bin/ +packages/ +paket-files/ +node_modules/ +*.orig +*.DotSettings.user +.git \ No newline at end of file diff --git a/build/Helpers.fs b/build/Helpers.fs new file mode 100644 index 0000000..9552ff2 --- /dev/null +++ b/build/Helpers.fs @@ -0,0 +1,122 @@ +module Helpers + +open Fake.Core + +let initializeContext () = + let execContext = Context.FakeExecutionContext.Create false "build.fsx" [ ] + Context.setExecutionContext (Context.RuntimeContext.Fake execContext) + +module Proc = + module Parallel = + open System + + let locker = obj() + + let colors = + [| ConsoleColor.Blue + ConsoleColor.Yellow + ConsoleColor.Magenta + ConsoleColor.Cyan + ConsoleColor.DarkBlue + ConsoleColor.DarkYellow + ConsoleColor.DarkMagenta + ConsoleColor.DarkCyan |] + + let print color (colored: string) (line: string) = + lock locker + (fun () -> + let currentColor = Console.ForegroundColor + Console.ForegroundColor <- color + Console.Write colored + Console.ForegroundColor <- currentColor + Console.WriteLine line) + + let onStdout index name (line: string) = + let color = colors.[index % colors.Length] + if isNull line then + print color $"{name}: --- END ---" "" + else if String.isNotNullOrEmpty line then + print color $"{name}: " line + + let onStderr name (line: string) = + let color = ConsoleColor.Red + if isNull line |> not then + print color $"{name}: " line + + let redirect (index, (name, createProcess)) = + createProcess + |> CreateProcess.redirectOutputIfNotRedirected + |> CreateProcess.withOutputEvents (onStdout index name) (onStderr name) + + let printStarting indexed = + for (index, (name, c: CreateProcess<_>)) in indexed do + let color = colors.[index % colors.Length] + let wd = + c.WorkingDirectory + |> Option.defaultValue "" + let exe = c.Command.Executable + let args = c.Command.Arguments.ToStartInfo + print color $"{name}: {wd}> {exe} {args}" "" + + let run cs = + cs + |> Seq.toArray + |> Array.indexed + |> fun x -> printStarting x; x + |> Array.map redirect + |> Array.Parallel.map Proc.run + +/// user interaction prompts for critical build tasks where you may want to interrupt when you see wrong inputs. +[] +module MessagePrompts = + + let prompt (msg:string) = + System.Console.Write(msg) + System.Console.ReadLine().Trim() + |> function | "" -> None | s -> Some s + |> Option.map (fun s -> s.Replace ("\"","\\\"")) + + let rec promptYesNo msg = + match prompt (sprintf "%s [Yn]: " msg) with + | Some "Y" | Some "y" -> true + | Some "N" | Some "n" -> false + | _ -> System.Console.WriteLine("Sorry, invalid answer"); promptYesNo msg + + let releaseMsg = """This will stage all uncommitted changes, push them to the origin and bump the release version to the latest number in the RELEASE_NOTES.md file. + Do you want to continue?""" + + let releaseDocsMsg = """This will push the docs to gh-pages. Remember building the docs prior to this. Do you want to continue?""" + +let createProcess exe arg dir = + CreateProcess.fromRawCommandLine exe arg + |> CreateProcess.withWorkingDirectory dir + |> CreateProcess.ensureExitCode + +let dotnet = createProcess "dotnet" + +let docker = createProcess "docker" + +let dockerCompose = createProcess "docker-compose" + +let run proc arg dir = + proc arg dir + |> Proc.run + |> ignore + +let runParallel processes = + processes + |> Proc.Parallel.run + |> ignore + +let runOrDefault args = + Trace.trace (sprintf "%A" args) + try + match args with + | [| target |] -> Target.runOrDefault target + | arr when args.Length > 1 -> + Target.run 0 (Array.head arr) ( Array.tail arr |> List.ofArray ) + | _ -> Target.runOrDefault "Build" + 0 + with e -> + printfn "%A" e + 1 diff --git a/build/PackageTasks.fs b/build/PackageTasks.fs new file mode 100644 index 0000000..ae1e346 --- /dev/null +++ b/build/PackageTasks.fs @@ -0,0 +1,165 @@ +module PackageTasks + +open Fake.Core +open Fake.DotNet +open Fake.IO.Globbing.Operators +open BlackFox +open BlackFox.Fake + +open ProjectInfo +open Helpers + +open BasicTasks +open TestTasks + +let pack = BuildTask.create "Pack" [clean; build; runTests; copyBinaries] { + if promptYesNo (sprintf "creating stable package with version %s OK?" stableVersionTag ) + then + !! "src/**/*.*proj" + |> Seq.iter (Fake.DotNet.DotNet.pack (fun p -> + let msBuildParams = + {p.MSBuildParams with + Properties = ([ + "Version",stableVersionTag + "PackageReleaseNotes", (release.Notes |> String.concat "\r\n") + ] @ p.MSBuildParams.Properties) + } + { + p with + MSBuildParams = msBuildParams + OutputPath = Some pkgDir + NoBuild = true + Configuration = DotNet.BuildConfiguration.fromString configuration + } + )) + else failwith "aborted" +} + +let packPrerelease = BuildTask.create "PackPrerelease" [setPrereleaseTag; clean; build; runTests; copyBinaries] { + if promptYesNo (sprintf "package tag will be %s OK?" prereleaseTag ) + then + !! "src/**/*.*proj" + //-- "src/**/Plotly.NET.Interactive.fsproj" + |> Seq.iter (Fake.DotNet.DotNet.pack (fun p -> + let msBuildParams = + {p.MSBuildParams with + Properties = ([ + "Version", prereleaseTag + "PackageReleaseNotes", (release.Notes |> String.toLines ) + ] @ p.MSBuildParams.Properties) + } + { + p with + VersionSuffix = Some prereleaseSuffix + OutputPath = Some pkgDir + NoBuild = true + Configuration = DotNet.BuildConfiguration.fromString configuration + } + )) + else + failwith "aborted" +} + +let publishBinariesWin = BuildTask.create "PublishBinariesWin" [clean.IfNeeded; build.IfNeeded] { + let outputPath = sprintf "%s/win-x64" publishDir + solutionFile + |> DotNet.publish (fun p -> + let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () + { + p with + Runtime = Some "win-x64" + Configuration = DotNet.BuildConfiguration.fromString configuration + OutputPath = Some outputPath + MSBuildParams = { + standardParams with + Properties = [ + "Version", stableVersionTag + "Platform", "x64" + "PublishSingleFile", "true" + ] + }; + } + ) + printfn "Beware that assemblyName differs from projectName!" +} + +let publishBinariesLinux = BuildTask.create "PublishBinariesLinux" [clean.IfNeeded; build.IfNeeded] { + let outputPath = sprintf "%s/linux-x64" publishDir + solutionFile + |> DotNet.publish (fun p -> + let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () + { + p with + Runtime = Some "linux-x64" + Configuration = DotNet.BuildConfiguration.fromString configuration + OutputPath = Some outputPath + MSBuildParams = { + standardParams with + Properties = [ + "Version", stableVersionTag + "Platform", "x64" + "PublishSingleFile", "true" + ] + } + } + ) + printfn "Beware that assemblyName differs from projectName!" +} + +let publishBinariesMac = BuildTask.create "PublishBinariesMac" [clean.IfNeeded; build.IfNeeded] { + let outputPath = sprintf "%s/osx-x64" publishDir + solutionFile + |> DotNet.publish (fun p -> + let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () + { + p with + Runtime = Some "osx-x64" + Configuration = DotNet.BuildConfiguration.fromString configuration + OutputPath = Some outputPath + MSBuildParams = { + standardParams with + Properties = [ + "Version", stableVersionTag + "Platform", "x64" + "PublishSingleFile", "true" + ] + } + } + ) + printfn "Beware that assemblyName differs from projectName!" +} + +let publishBinariesMacARM = BuildTask.create "PublishBinariesMacARM" [clean.IfNeeded; build.IfNeeded] { + let outputPath = sprintf "%s/osx-arm64" publishDir + solutionFile + |> DotNet.publish (fun p -> + let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () + { + p with + Runtime = Some "osx.12-arm64" + Configuration = DotNet.BuildConfiguration.fromString configuration + OutputPath = Some outputPath + MSBuildParams = { + standardParams with + Properties = [ + "Version", stableVersionTag + //"Platform", "arm64" // throws MSBuild Error although it should work: error MSB4126: The specified solution configuration "Release|ARM64" is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties blank to use the default solution configuration. [C:\Repos\omaus\arcCommander\ArcCommander.sln] + "PublishSingleFile", "true" + ] + } + } + ) + printfn "Beware that assemblyName differs from projectName!" +} + +let publishBinariesAll = BuildTask.createEmpty "PublishBinariesAll" [clean; build; publishBinariesWin; publishBinariesLinux; publishBinariesMac; publishBinariesMacARM] + +let publishBinariesMacBoth = BuildTask.createEmpty "PublishBinariesMacBoth" [clean; build; publishBinariesMac; publishBinariesMacARM] + +// as of now (july 2022), it seems there is now possibility to run lipo on Windows +//let packMacBinaries = BuildTask.create "PackMacBinaries" [publishBinariesMacBoth] { +// let pr = new System.Diagnostics.Process() +// pr.StartInfo.FileName <- "lipo" +// pr.StartInfo.Arguments <- "-create -output ArcCommander ./" // TO DO: add filepaths to both executables (see https://www.kenmuse.com/blog/notarizing-dotnet-console-apps-for-macos/ Chapter "Creating Universal binaries" +// pr.Start() |> ignore +//} \ No newline at end of file diff --git a/build/ProjectInfo.fs b/build/ProjectInfo.fs new file mode 100644 index 0000000..15e3d65 --- /dev/null +++ b/build/ProjectInfo.fs @@ -0,0 +1,44 @@ +module ProjectInfo + +open Fake.Core +open Fake.IO + +// run this here to make sure a RELEASE_NOTES.md exists, otherwise "let release = ReleaseNotes.load "RELEASE_NOTES.md" will fail. +Fake.Extensions.Release.ReleaseNotes.ensure() + +let project = "ArcCommander" + +let testProject = Path.getFullName "tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj" + +let summary = "ArcCommander is a command line tool to create, manage and share your ARCs." + +let solutionFile = Path.getFullName "ArcCommander.sln" + +let configuration = "Release" + +// Git configuration (used for publishing documentation in gh-pages branch) +// The profile where the project is posted +let gitOwner = "nfdi4plants" +let gitHome = sprintf "%s/%s" "https://github.com" gitOwner + +let gitName = "arcCommander" + +let website = "/arcCommander" + +let pkgDir = Path.getFullName "pkg" + +let publishDir = "publish" + +let release = ReleaseNotes.load "RELEASE_NOTES.md" + +let projectRepo = "https://github.com/nfdi4plants/arcCommander" + +let stableVersion = SemVer.parse release.NugetVersion + +let stableVersionTag = (sprintf "%i.%i.%i" stableVersion.Major stableVersion.Minor stableVersion.Patch ) + +let mutable prereleaseSuffix = "" + +let mutable prereleaseTag = "" + +let mutable isPrerelease = false \ No newline at end of file diff --git a/build/ReleaseNoteTasks.fs b/build/ReleaseNoteTasks.fs new file mode 100644 index 0000000..aaebccc --- /dev/null +++ b/build/ReleaseNoteTasks.fs @@ -0,0 +1,48 @@ +module ReleaseNoteTasks + +open Fake.Core +open Fake.IO +open BlackFox.Fake + +open Fake.Extensions.Release + +let updateVersionOfReleaseWorkflow (stableVersionTag) = + printfn "Start updating release-github workflow to version %s" stableVersionTag + let filePath = Path.getFullName ".github/workflows/release-github.yml" + let s = File.readAsString filePath + let lastVersion = System.Text.RegularExpressions.Regex.Match(s,@"v\d+.\d+.\d+").Value + s.Replace(lastVersion,$"v{stableVersionTag}") + |> File.writeString false filePath + +let updateReleaseNotes = BuildTask.createFn "ReleaseNotes" [] (fun config -> + ReleaseNotes.ensure() + + ReleaseNotes.update(ProjectInfo.gitOwner, ProjectInfo.gitName, config) + + let release = ReleaseNotes.load "RELEASE_NOTES.md" + + Fake.DotNet.AssemblyInfoFile.createFSharp "src/arcCommander/Server/Version.fs" + [ Fake.DotNet.AssemblyInfo.Title "ArcCommander" + Fake.DotNet.AssemblyInfo.Version release.AssemblyVersion + Fake.DotNet.AssemblyInfo.Metadata ("ReleaseDate", release.Date |> Option.defaultValue System.DateTime.Today |> fun d -> d.ToShortDateString()) + ] + + let stableVersion = SemVer.parse release.NugetVersion + + let stableVersionTag = (sprintf "%i.%i.%i" stableVersion.Major stableVersion.Minor stableVersion.Patch ) + + updateVersionOfReleaseWorkflow (stableVersionTag) +) + +let githubDraft = BuildTask.createFn "GithubDraft" [] (fun config -> + + let body = "We are ready to go for the first release!" + + Github.draft( + ProjectInfo.gitOwner, + ProjectInfo.gitName, + (Some body), + None, + config + ) +) diff --git a/build/ReleaseTasks.fs b/build/ReleaseTasks.fs new file mode 100644 index 0000000..1f22be5 --- /dev/null +++ b/build/ReleaseTasks.fs @@ -0,0 +1,82 @@ +module ReleaseTasks + +open Fake.Core +open Fake.DotNet +open Fake.IO.Globbing.Operators +open BlackFox.Fake +open Fake.Tools + +open ProjectInfo +open Helpers + +open BasicTasks +open TestTasks +open PackageTasks + +let createTag = BuildTask.create "CreateTag" [clean; build; copyBinaries; runTests; pack] { + if promptYesNo (sprintf "tagging branch with %s OK?" stableVersionTag ) then + Git.Branches.tag "" stableVersionTag + Git.Branches.pushTag "" projectRepo stableVersionTag + else + failwith "aborted" +} + +let createPrereleaseTag = BuildTask.create "CreatePrereleaseTag" [setPrereleaseTag; clean; build; copyBinaries; runTests; packPrerelease] { + if promptYesNo (sprintf "tagging branch with %s OK?" prereleaseTag ) then + Git.Branches.tag "" prereleaseTag + Git.Branches.pushTag "" projectRepo prereleaseTag + else + failwith "aborted" +} + +let publishNuget = BuildTask.create "PublishNuget" [clean; build; copyBinaries; runTests; pack] { + let targets = (!! (sprintf "%s/*.*pkg" pkgDir )) + for target in targets do printfn "%A" target + let msg = sprintf "release package with version %s?" stableVersionTag + if promptYesNo msg then + let source = "https://api.nuget.org/v3/index.json" + let apikey = Environment.environVar "NUGET_KEY" + for artifact in targets do + let result = DotNet.exec id "nuget" (sprintf "push -s %s -k %s %s --skip-duplicate" source apikey artifact) + if not result.OK then failwith "failed to push packages" + else failwith "aborted" +} + +let publishNugetPrerelease = BuildTask.create "PublishNugetPrerelease" [clean; build; copyBinaries; runTests; packPrerelease] { + let targets = (!! (sprintf "%s/*.*pkg" pkgDir )) + for target in targets do printfn "%A" target + let msg = sprintf "release package with version %s?" prereleaseTag + if promptYesNo msg then + let source = "https://api.nuget.org/v3/index.json" + let apikey = Environment.environVar "NUGET_KEY" + for artifact in targets do + let result = DotNet.exec id "nuget" (sprintf "push -s %s -k %s %s --skip-duplicate" source apikey artifact) + if not result.OK then failwith "failed to push packages" + else failwith "aborted" +} + +//let releaseDocs = BuildTask.create "ReleaseDocs" [buildDocs] { +// let msg = sprintf "release docs for version %s?" stableVersionTag +// if promptYesNo msg then +// Shell.cleanDir "temp" +// Git.CommandHelper.runSimpleGitCommand "." (sprintf "clone %s temp/gh-pages --depth 1 -b gh-pages" projectRepo) |> ignore +// Shell.copyRecursive "output" "temp/gh-pages" true |> printfn "%A" +// Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" "add ." |> printfn "%s" +// let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" stableVersionTag +// Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" cmd |> printfn "%s" +// Git.Branches.push "temp/gh-pages" +// else failwith "aborted" +//} + +//let prereleaseDocs = BuildTask.create "PrereleaseDocs" [buildDocsPrerelease] { +// let msg = sprintf "release docs for version %s?" prereleaseTag +// if promptYesNo msg then +// Shell.cleanDir "temp" +// Git.CommandHelper.runSimpleGitCommand "." (sprintf "clone %s temp/gh-pages --depth 1 -b gh-pages" projectRepo) |> ignore +// Shell.copyRecursive "output" "temp/gh-pages" true |> printfn "%A" +// Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" "add ." |> printfn "%s" +// let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" prereleaseTag +// Git.CommandHelper.runSimpleGitCommand "temp/gh-pages" cmd |> printfn "%s" +// Git.Branches.push "temp/gh-pages" +// else failwith "aborted" +//} \ No newline at end of file diff --git a/build/TestTasks.fs b/build/TestTasks.fs new file mode 100644 index 0000000..42e83c9 --- /dev/null +++ b/build/TestTasks.fs @@ -0,0 +1,31 @@ +module TestTasks + +open BlackFox.Fake + +open ProjectInfo +open BasicTasks +open Helpers +open System.IO + +let runTests = BuildTask.createFn "RunTests" [clean; cleanTestResults; build; copyBinaries] (fun config -> + let isWatch = + config.Context.Arguments + |> List.exists (fun x -> x.ToLower() = "watch") + + let singleRunTestsCommand = $"run --project tests{Path.DirectorySeparatorChar}ArcCommander.Tests.NetCore" + let watchRunTestsCommand = "watch " + singleRunTestsCommand + + if isWatch then + run dotnet watchRunTestsCommand "" + else + run dotnet singleRunTestsCommand "" + //let standardParams = Fake.DotNet.MSBuild.CliArguments.Create () + //Fake.DotNet.DotNet.test(fun testParams -> + // { + // testParams with + // Logger = Some "console;verbosity=detailed" + // Configuration = DotNet.BuildConfiguration.fromString configuration + // NoBuild = true + // } + //) testProject +) diff --git a/build/ToolTasks.fs b/build/ToolTasks.fs new file mode 100644 index 0000000..700ef48 --- /dev/null +++ b/build/ToolTasks.fs @@ -0,0 +1,18 @@ +module ToolTasks + +open Fake.IO +open BlackFox.Fake + +open ProjectInfo +open Helpers +open PackageTasks + +let installPackagedTool = BuildTask.create "InstallPackagedTool" [packPrerelease] { + Directory.ensure "tests/tool-tests" + run dotnet "new tool-manifest --force" "tests/tool-tests" + run dotnet (sprintf "tool install --add-source ../../%s ArcCommander --version %s" pkgDir prereleaseTag) "tests/tool-tests" +} + +let testPackagedTool = BuildTask.create "TestPackagedTool" [installPackagedTool] { + run dotnet "ArcCommander --help" "tests/tool-tests" +} \ No newline at end of file diff --git a/createTemplateArc.cmd b/createTemplateArc.cmd deleted file mode 100644 index b1ba766..0000000 --- a/createTemplateArc.cmd +++ /dev/null @@ -1,4 +0,0 @@ -arc init -arc i create -arc s add -arc a add \ No newline at end of file diff --git a/createTemplateArc.sh b/createTemplateArc.sh deleted file mode 100644 index b1ba766..0000000 --- a/createTemplateArc.sh +++ /dev/null @@ -1,4 +0,0 @@ -arc init -arc i create -arc s add -arc a add \ No newline at end of file diff --git a/docs/_template.html b/docs/_template.html deleted file mode 100644 index f2b2b16..0000000 --- a/docs/_template.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - {{fsdocs-page-title}} - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- {{fsdocs-content}} - {{fsdocs-tooltips}} -
- - - - - - - - -
- - - - diff --git a/docs/content/FSharpSpreadsheetML.fsx b/docs/content/FSharpSpreadsheetML.fsx deleted file mode 100644 index fd0231a..0000000 --- a/docs/content/FSharpSpreadsheetML.fsx +++ /dev/null @@ -1,36 +0,0 @@ -(*** hide ***) -// This block of code is omitted in the generated HTML documentation. Use -// it to define helpers that you do not want to show in the documentation. -#I @"../../bin\ArcCommander\netcoreapp3.1" -#r "DocumentFormat.OpenXml.dll" -#r"FSharpSpreadsheetML.dll" - -open DocumentFormat.OpenXml -open DocumentFormat.OpenXml.Packaging -open DocumentFormat.OpenXml.Spreadsheet -open FSharpSpreadsheetML - -/// Create new copy of the textXLSX -let doc = - let source = Spreadsheet.openSpreadsheet @"C:\Users\HLWei\source\repos\arcCommander\docs\content\data\FSharpSpreadsheetMLTest.xlsx" false - source |> Spreadsheet.saveAs @"C:\Users\HLWei\source\repos\arcCommander\docs\content\data\FSharpSpreadsheetMLTestCopy.xlsx" - source |> Spreadsheet.close - Spreadsheet.openSpreadsheet @"C:\Users\HLWei\source\repos\arcCommander\docs\content\data\FSharpSpreadsheetMLTestCopy.xlsx" true - -let workBookPart = Spreadsheet.getWorkbookPart doc - -let sheet = SheetTransformation.firstSheetOfWorkbookPart workBookPart - -SheetTransformation.SSTSheets.getCellValueSSTAt workBookPart 1u 1u sheet - -SheetTransformation.SSTSheets.getRowValuesSSTAt workBookPart 2u sheet - -SheetTransformation.DirectSheets.insertRowAt ["omg";"this";"is";"test"] 2u sheet - -SheetTransformation.DirectSheets.appendRow ["last";"row";"in";"doc"] sheet - -SheetTransformation.DirectSheets.removeRowAt 3u sheet - -doc -|> Spreadsheet.saveChanges -|> Spreadsheet.close \ No newline at end of file diff --git a/docs/content/ISA_XLSX.IO.fsx b/docs/content/ISA_XLSX.IO.fsx deleted file mode 100644 index e1697e6..0000000 --- a/docs/content/ISA_XLSX.IO.fsx +++ /dev/null @@ -1,82 +0,0 @@ - -//#load "C:\Users\HLWei\source\diverse\OpenXML\.paket\load\DocumentFormat.OpenXml.fsx" -#I @"../../bin\ArcCommander\netcoreapp3.1" - -#r "DocumentFormat.OpenXml.dll" -#r"FSharpSpreadsheetML.dll" -#r "ISA-XLSX.dll" - -open DocumentFormat.OpenXml -open DocumentFormat.OpenXml.Packaging -open DocumentFormat.OpenXml.Spreadsheet -open FSharpSpreadsheetML - -open ISA -open DataModel -open InvestigationFile -open ISA_XLSX.IO - -let source = __SOURCE_DIRECTORY__ - -//let investPath = source + @"C:\Users\HLWei\source\diverse\XLSXUnzip\i_investigation - Copy.xlsx" - -//let path = @"C:\Users\HLWei\source\diverse\XLSXUnzip\test.xlsx" - -//InvestigationItem(identifier = "lul") -//|> ISA_Investigation.createEmpty (path) - - -//let doc = Spreadsheet.openSpreadsheet path true - - - - -//ISA_Investigation.addStudy (StudyItem(identifier = "Study1",submissionDate = "1.2.3")) doc - -//ISA_Investigation.tryAddItemToStudy (Factor(name = "Factor1",factorType = "dwadw")) "Study1" doc - -//ISA_Investigation.tryAddItemToStudy (Factor(name = "Factor2",factorType = "ebeb")) "Study1" doc - -//ISA_Investigation.tryAddItemToStudy (Assay(FileName ="2")) "Study1" doc - -//ISA_Investigation.tryRemoveItemFromStudy (Factor(name = "Factor1")) "Study1" doc - -//ISA_Investigation.tryUpdateItemInStudy (Factor(name = "Factor2",factorType = "degebab",typeTermAccessionNumber = "5")) "Study1" doc - -//ISA_Investigation.tryAddItemToStudy (Person(firstName = "Max",lastName = "Mus")) "Study1" doc -//ISA_Investigation.tryAddItemToStudy (Person(firstName = "Tim",lastName = "Taler")) "Study1" doc -//ISA_Investigation.tryUpdateItemInStudy (Person(firstName = "Max",lastName = "Mus",phone = "12345")) "Study1" doc - - -//doc.Close() - -//open ISA_Investigation - -//let item = (Factor(name = "Factor1")) :> ISAItem -//let study = "Study1" - - -//let workbookPart = doc |> Spreadsheet.getWorkbookPart - -//let sheet = SheetTransformation.firstSheetOfWorkbookPart workbookPart - - -//let studyScope = tryGetStudyScope workbookPart study sheet - -//let itemScope = -// studyScope -// |> Option.map (fun studyScope -> tryGetItemScope workbookPart study studyScope item sheet) -// |> Option.flatten -// |> Option.get - - -//let colI = tryFindColumnInItemScope workbookPart "Study" itemScope item sheet |> Option.get - -//[itemScope.From .. itemScope.To] -//|> List.rev -//|> List.fold (fun s rowI -> SheetTransformation.DirectSheets.removeValueAt colI rowI s) sheet -//|> removeScopeIfEmpty workbookPart itemScope - -//[1] -//|> Seq.skip 2 - diff --git a/docs/content/data/FSharpSpreadsheetMLTest.xlsx b/docs/content/data/FSharpSpreadsheetMLTest.xlsx deleted file mode 100644 index 91675ae..0000000 Binary files a/docs/content/data/FSharpSpreadsheetMLTest.xlsx and /dev/null differ diff --git a/docs/content/data/FSharpSpreadsheetMLTestCopy.xlsx b/docs/content/data/FSharpSpreadsheetMLTestCopy.xlsx deleted file mode 100644 index af02606..0000000 Binary files a/docs/content/data/FSharpSpreadsheetMLTestCopy.xlsx and /dev/null differ diff --git a/docs/content/fsdocs-custom.css b/docs/content/fsdocs-custom.css deleted file mode 100644 index 3f4834a..0000000 --- a/docs/content/fsdocs-custom.css +++ /dev/null @@ -1,209 +0,0 @@ -/* Navigation Pane */ - -#navbarsExampleDefault .nav-header { - font-size:12pt; - color:#606060; - margin-top:20px; - font-weight: bold; -} - -#navbarsExampleDefault .nav-link { - font-size:11pt; - color:#0088cc; -} - - -/* FSharp Code scrollbar */ - -table.pre { - border: hidden; - overflow-x: auto; - white-space: nowrap; - display:block; -} - -table.pre::-webkit-scrollbar-track -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - border-radius: 5px; - background-color: #212d30; -} - -table.pre::-webkit-scrollbar -{ - height: 8px; - background-color: #212d30; - border-radius:5px -} - -table.pre::-webkit-scrollbar-thumb -{ - border-radius: 5px; - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background-color: #80b0b0; -} - -pre { - border: hidden; - overflow-x: auto; -} - -pre::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - border-radius: 5px; - background-color: #212d30; -} - -pre::-webkit-scrollbar { - height: 8px; - background-color: #212d30; - border-radius: 5px -} - -pre::-webkit-scrollbar-thumb { - border-radius: 5px; - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background-color: #80b0b0; -} -#main -{ - text-align:justify; -} - -#main h2 -{ - margin: 10px 0px 10px 0px; -} - -#responsiveTable -{ - overflow-x:auto; -} - -#responsiveTable::-webkit-scrollbar-track -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - border-radius: 5px; - background-color: #212d30; -} - -#responsiveTable::-webkit-scrollbar -{ - height: 8px; - background-color: #212d30; - border-radius:5px -} - -#responsiveTable::-webkit-scrollbar-thumb -{ - border-radius: 5px; - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background-color: #80b0b0; -} - -#responsiveTable p -{ - margin: 0px 0px 0px 0px; -} - -#responsiveTable table -{ - border: 2px solid #2E75B6; - border-radius:50px; -} - -#responsiveTable tr:nth-child(even) -{ - background-color: #BDD7EE; -} - -#responsiveTable tr -{ - border: 1px solid #2E75B6; -} - -#responsiveTable th -{ - background-color:#2E75B6; - color:white; -} - -#responsiveTable th, td -{ - text-align: left; - padding: 0px 10px 0px 10px; -} - -.fileExamples -{ - overflow-x: auto; - white-space: nowrap; - display:block; - -} - -.fileExamples pre -{ - background-color: white; - color:black; -} - -.fileExamples::-webkit-scrollbar-track -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - border-radius: 5px; - background-color: #212d30; -} - -.fileExamples::-webkit-scrollbar -{ - height: 8px; - background-color: #212d30; - border-radius:5px -} - -.fileExamples::-webkit-scrollbar-thumb -{ - border-radius: 5px; - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background-color: #80b0b0; -} - -#exampleToggle -{ - border-color: #2E75B6; -} - -#SourceCode, #Author, #APILink -{ - text-align:center; - color:#2E75B6; - padding: 2px 6px 2px 6px; - /*border-radius: 25px; - border: 2px solid #2E75B6;*/ - text-decoration:none; - -} - - - -#Author:hover, #SourceCode:hover , #APILink:hover -{ - background-color:#2E75B6; - color:white; -} - - - -table.HeadAPI { - width: 100% -} - -td.Head { - padding: 0px; -} - -td.API { - padding: 0px; - text-align: right; -} diff --git a/docs/content/img/logo.png b/docs/content/img/logo.png deleted file mode 100644 index 2dcecfb..0000000 Binary files a/docs/content/img/logo.png and /dev/null differ diff --git a/docs/content/index.fsx b/docs/content/index.fsx deleted file mode 100644 index 85c3f15..0000000 --- a/docs/content/index.fsx +++ /dev/null @@ -1,22 +0,0 @@ -(*** hide ***) -// This block of code is omitted in the generated HTML documentation. Use -// it to define helpers that you do not want to show in the documentation. - -#I @"../../bin\ArcCommander\netcoreapp3.1" -#r"FSharpSpreadsheetML.dll" - -open FSharpSpreadsheetML -(** -# ArcCommander - - -FSharp Library - -
- ---- -*) - - -Array.init 10 (fun i -> i, i * 2) -(*** include-it ***) \ No newline at end of file diff --git a/global.json b/global.json index 7abee74..08fc58c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.100", - "rollForward": "latestMajor" + "version": "6.0.100", + "rollForward": "latestMinor" } } \ No newline at end of file diff --git a/publishBinariesLnx.cmd b/publishBinariesLnx.cmd deleted file mode 100644 index 4589f1b..0000000 --- a/publishBinariesLnx.cmd +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -dotnet fake build -t publishBinariesLinux -echo DONE! -timeout 5 >nul \ No newline at end of file diff --git a/publishBinariesMac.cmd b/publishBinariesMac.cmd deleted file mode 100644 index 22bd08c..0000000 --- a/publishBinariesMac.cmd +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -dotnet fake build -t publishBinariesMac -echo DONE! -timeout 5 >nul \ No newline at end of file diff --git a/publishBinariesWin.cmd b/publishBinariesWin.cmd deleted file mode 100644 index 096a8b3..0000000 --- a/publishBinariesWin.cmd +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -dotnet fake build -t publishBinariesWin -echo DONE! -timeout 5 >nul \ No newline at end of file diff --git a/src/ArcCommander/.gitignore b/src/ArcCommander/.gitignore deleted file mode 100644 index aba35e3..0000000 --- a/src/ArcCommander/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# exclude everything.. -* -#.. except .. - - -#Include ARC folders -!.arc/ -!.arc/** -!assays/ -!assays/** -!studies/ -!studies/** -!workflows/ -!workflows/** -!runs/ -!runs/** - - -#Include ARC top level files -!.gitattributes -!.gitignore -!README.md - - -#Include ISA top level files -!isa.investigation.xlsx -!*isa.study.xlsx diff --git a/src/ArcCommander/APIs/ArcAPI.fs b/src/ArcCommander/APIs/ArcAPI.fs index aa134be..0213d13 100644 --- a/src/ArcCommander/APIs/ArcAPI.fs +++ b/src/ArcCommander/APIs/ArcAPI.fs @@ -8,6 +8,22 @@ open ArcCommander.ArgumentProcessing open ISADotNet open ISADotNet.XLSX +open arcIO.NET +open arcIO.NET.Converter + +module API = + + module Investigation = + + let getProcesses (investigation) = + investigation.Studies + |> Option.defaultValue [] |> List.collect (fun s -> + s.Assays + |> Option.defaultValue [] |> List.collect (fun a -> + a.ProcessSequence |> Option.defaultValue [] + ) + ) + /// ArcCommander API functions that get executed by top level subcommand verbs. module ArcAPI = @@ -73,7 +89,8 @@ module ArcAPI = //GitHelper.executeGitCommand workDir $"commit -m \"Initial commit\"" if containsFlag "Gitignore" arcArgs then - let gitignoreAppPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".gitignore") + log.Warn("The default GitIgnore is an experimental feature. Be careful and double check that all your wanted files are being tracked.") + let gitignoreAppPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "defaultGitignore") let gitignoreArcPath = Path.Combine(workDir, ".gitignore") log.Trace($"Copy .gitignore from {gitignoreAppPath} to {gitignoreArcPath}") File.Copy(gitignoreAppPath, gitignoreArcPath) @@ -97,52 +114,10 @@ module ArcAPI = log.Info("Start Arc Update") - let assayRootFolder = AssayConfiguration.getRootFolderPath arcConfiguration - - let investigationFilePath = IsaModelConfiguration.getInvestigationFilePath arcConfiguration - - let assayNames = - DirectoryInfo(assayRootFolder).GetDirectories() - |> Array.map (fun d -> d.Name) - - let investigation = - try Investigation.fromFile investigationFilePath - with - | :? FileNotFoundException -> - Investigation.empty - | err -> - log.Fatal($"{err.ToString()}") - raise (Exception("")) - - let rec updateInvestigationAssays (assayNames : string list) (investigation : Investigation) = - match assayNames with - | a :: t -> - let assayFilePath = IsaModelConfiguration.getAssayFilePath a arcConfiguration - let assayFileName = IsaModelConfiguration.getAssayFileName a arcConfiguration - let factors,protocols,persons,assay = AssayFile.Assay.fromFile assayFilePath - let studies = investigation.Studies - - match studies with - | Some studies -> - match studies |> Seq.tryFind (API.Study.getAssays >> Option.defaultValue [] >> API.Assay.existsByFileName assayFileName) with - | Some study -> - study - |> API.Study.mapAssays (API.Assay.updateByFileName API.Update.UpdateByExistingAppendLists assay) - |> API.Study.mapFactors (List.append factors >> List.distinctBy (fun f -> f.Name)) - |> API.Study.mapProtocols (List.append protocols >> List.distinctBy (fun p -> p.Name)) - |> API.Study.mapContacts (List.append persons >> List.distinctBy (fun p -> p.FirstName,p.LastName)) - |> fun s -> API.Study.updateBy ((=) study) API.Update.UpdateAll s studies - | None -> - Study.fromParts (Study.StudyInfo.create a "" "" "" "" "" []) [] [] factors [assay] protocols persons - |> API.Study.add studies - | None -> - [Study.fromParts (Study.StudyInfo.create a "" "" "" "" "" []) [] [] factors [assay] protocols persons] - |> API.Investigation.setStudies investigation - |> updateInvestigationAssays t - | [] -> investigation - - updateInvestigationAssays (assayNames |> List.ofArray) investigation - |> Investigation.toFile investigationFilePath + let arcDir = GeneralConfiguration.getWorkDirectory arcConfiguration + + Investigation.fromArcFolder arcDir + |> Investigation.overWrite arcDir /// Export the complete ARC as a JSON object. let export (arcConfiguration : ArcConfiguration) (arcArgs : Map) = @@ -151,73 +126,82 @@ module ArcAPI = log.Info("Start Arc Export") - let investigationFilePath = IsaModelConfiguration.getInvestigationFilePath arcConfiguration - - let assayNames = AssayConfiguration.getAssayNames arcConfiguration - - let investigation = - try Investigation.fromFile investigationFilePath - with - | :? FileNotFoundException -> - Investigation.empty - | err -> - log.Fatal($"{err.Message}") - raise (Exception("")) - - let rec updateInvestigationAssays (assayNames : string list) (investigation : Investigation) = - match assayNames with - | a :: t -> - let assayFilePath = IsaModelConfiguration.getAssayFilePath a arcConfiguration - let assayFileName = (IsaModelConfiguration.getAssayFileName a arcConfiguration).Replace("\\","/") - let factors,protocols,persons,assay = AssayFile.Assay.fromFile assayFilePath - let studies = investigation.Studies - - match studies with - | Some studies -> - match studies |> Seq.tryFind (API.Study.getAssays >> Option.defaultValue [] >> API.Assay.existsByFileName assayFileName) with - | Some study -> - study - |> API.Study.mapAssays (API.Assay.updateByFileName API.Update.UpdateByExistingAppendLists assay) - |> API.Study.mapFactors (List.append factors >> List.distinctBy (fun f -> f.Name)) - |> API.Study.mapProtocols (List.append protocols >> List.distinctBy (fun p -> p.Name)) - |> API.Study.mapContacts (List.append persons >> List.distinctBy (fun p -> p.FirstName,p.LastName)) - |> fun s -> API.Study.updateBy ((=) study) API.Update.UpdateAll s studies - | None -> - Study.fromParts (Study.StudyInfo.create a "" "" "" "" "" []) [] [] factors [assay] protocols persons - |> API.Study.add studies - | None -> - [Study.fromParts (Study.StudyInfo.create a "" "" "" "" "" []) [] [] factors [assay] protocols persons] - |> API.Investigation.setStudies investigation - |> updateInvestigationAssays t - | [] -> investigation - - let output = updateInvestigationAssays (assayNames |> List.ofArray) investigation + let workDir = GeneralConfiguration.getWorkDirectory arcConfiguration + + let investigation = arcIO.NET.Investigation.fromArcFolder workDir if containsFlag "ProcessSequence" arcArgs then - let output = - output.Studies - |> Option.defaultValue [] |> List.collect (fun s -> - s.Assays - |> Option.defaultValue [] |> List.collect (fun a -> - a.ProcessSequence |> Option.defaultValue [] - ) - ) + let output = API.Investigation.getProcesses investigation match tryGetFieldValueByName "Output" arcArgs with | Some p -> ArgumentProcessing.serializeToFile p output | None -> () - //System.Console.Write(ArgumentProcessing.serializeToString output) log.Debug(ArgumentProcessing.serializeToString output) else - + match tryGetFieldValueByName "Output" arcArgs with - | Some p -> ISADotNet.Json.Investigation.toFile p output + | Some p -> ISADotNet.Json.Investigation.toFile p investigation | None -> () - //System.Console.Write(ISADotNet.Json.Investigation.toString output) - log.Debug(ISADotNet.Json.Investigation.toString output) + log.Debug(ISADotNet.Json.Investigation.toString investigation) + + /// Convert the complete ARC to a target format. + let convert (arcConfiguration : ArcConfiguration) (arcArgs : Map) = + + let log = Logging.createLogger "ArcConvertLog" + + log.Info("Start Arc Convert") + + let workDir = GeneralConfiguration.getWorkDirectory arcConfiguration + + let nameRoot = getFieldValueByName "Target" arcArgs + let converterName = $"arc-convert-{nameRoot}" + let repoOwner = "nfdi4plants" + let repoName = "converters" + + log.Info (converterName) + + let assayIdentifier = tryGetFieldValueByName "AssayIdentifier" arcArgs + let studyIdentifier = tryGetFieldValueByName "StudyIdentifier" arcArgs + + log.Info("Fetch converter dll") + + let assembly = + if nameRoot.Contains ".dll" then + System.Reflection.Assembly.LoadFile nameRoot + else + let dll = ArcConversion.getDll repoOwner repoName $"{converterName}.dll" + System.Reflection.Assembly.Load dll + let converter = + ArcConversion.callMethodOfAssembly converterName "create" assembly :?> ARCconverter + log.Info("Load ARC") + + let i,s,a = ArcConversion.getISA studyIdentifier assayIdentifier workDir + + log.Info("Run conversion") + + match converter with + | ARCtoCSV f -> + ArcConversion.handleCSV i s a workDir nameRoot converter + | ARCtoTSV f -> + ArcConversion.handleTSV i s a workDir nameRoot converter + | ARCtoXLSX f -> + ArcConversion.handleXLSX i s a workDir nameRoot converter + | ARCtoJSON f -> + ArcConversion.handleJSON i s a workDir nameRoot converter + | _ -> failwith "no other converter defined" + |> function + | Ok messages -> + log.Info $"Successfully converted to {nameRoot}" + ArcConversion.writeMessages workDir messages + | Error messages -> + ArcConversion.writeMessages workDir messages + log.Error $"Arc could not be converted to {nameRoot}, as some required values could not be retreived" + if ArcConversion.promptYesNo "Do you want missing fields to be written back into ARC? (y/n)" then + ArcConversion.handleTransformations workDir converterName messages + /// Returns true if called anywhere in an ARC. let isArc (arcConfiguration : ArcConfiguration) (arcArgs : Map) = raise (NotImplementedException()) \ No newline at end of file diff --git a/src/ArcCommander/APIs/AssayAPI.fs b/src/ArcCommander/APIs/AssayAPI.fs index 029acb8..baa5efe 100644 --- a/src/ArcCommander/APIs/AssayAPI.fs +++ b/src/ArcCommander/APIs/AssayAPI.fs @@ -10,7 +10,8 @@ open ISADotNet open ISADotNet.XLSX open ISADotNet.XLSX.AssayFile -open FSharpSpreadsheetML +open FsSpreadsheet.ExcelIO +open arcIO.NET /// ArcCommander Assay API functions that get executed by the assay focused subcommand verbs module AssayAPI = @@ -205,7 +206,7 @@ module AssayAPI = assay1.Comments = assay2.Comments // read assay metadata information from assay file - let _, _, _, oldAssayAssayFile = AssayFile.Assay.fromFile assayFilepath + let _, oldAssayAssayFile = AssayFile.Assay.fromFile assayFilepath let getNewAssay oldAssay = ArgumentProcessing.Prompt.createIsaItemQuery @@ -273,7 +274,7 @@ module AssayAPI = let assayFilePath = IsaModelConfiguration.getAssayFilePath assayIdentifier arcConfiguration - let _, _, _, assay = Assay.fromFile assayFilePath + let _, assay = Assay.fromFile assayFilePath let studyIdentifier = match getFieldValueByName "StudyIdentifier" assayArgs with @@ -309,6 +310,7 @@ module AssayAPI = let info = Study.StudyInfo.create studyIdentifier "" "" "" "" (IsaModelConfiguration.getStudyFileName studyIdentifier arcConfiguration) [] Study.fromParts info [] [] [] [assay] [] [] |> API.Study.add studies + |> List.filter (fun s -> s <> Study.empty) | None -> log.Info($"Study with the identifier {studyIdentifier} does not exist yet, creating it now.") if StudyAPI.StudyFile.exists arcConfiguration studyIdentifier |> not then @@ -657,7 +659,7 @@ module AssayAPI = if System.IO.File.Exists assayFilePath then try - let _, _, p, a = AssayFile.Assay.fromFile assayFilePath + let p, a = AssayFile.Assay.fromFile assayFilePath p, Some a with | err -> @@ -753,7 +755,7 @@ module AssayAPI = if System.IO.File.Exists assayFilePath then try - let _,_,p,a = AssayFile.Assay.fromFile assayFilePath + let p,a = AssayFile.Assay.fromFile assayFilePath p, Some a with | err -> diff --git a/src/ArcCommander/APIs/ConfigurationAPI.fs b/src/ArcCommander/APIs/ConfigurationAPI.fs index 6cea7eb..f20287b 100644 --- a/src/ArcCommander/APIs/ConfigurationAPI.fs +++ b/src/ArcCommander/APIs/ConfigurationAPI.fs @@ -2,6 +2,7 @@ open ArcCommander open ArgumentProcessing +open arcIO.NET /// ArcCommander Configuration API functions that get executed by the configuration focused subcommand verbs module ConfigurationAPI = diff --git a/src/ArcCommander/APIs/ExternalExecutables.fs b/src/ArcCommander/APIs/ExternalExecutables.fs index e80036d..fdd61cd 100644 --- a/src/ArcCommander/APIs/ExternalExecutables.fs +++ b/src/ArcCommander/APIs/ExternalExecutables.fs @@ -6,6 +6,7 @@ open System open System.IO open System.Diagnostics open Argu +open arcIO.NET /// Functions for trying to run external tools, given the command line arguments can not be parsed. module ExternalExecutables = @@ -82,9 +83,9 @@ module ExternalExecutables = let roev = reviseOutput ev.Data if matchCmdErrMsg roev || matchBashErrMsg roev then log.Error("No executable, command or script file with given argument name known.") - handleExceptionMessage log e2 + Logging.handleExceptionMessage log e2 raise (Exception()) - else checkNonLog roev (sprintf "External Tool ERROR: %s" >> log.Error) + else Logging.checkNonLog roev (sprintf "External Tool ERROR: %s" >> log.Error) ) let sbOutput = Text.StringBuilder() // StringBuilder for TRACE output (verbosity 2) sbOutput.Append("External tool: ") |> ignore @@ -98,9 +99,9 @@ module ExternalExecutables = sbOutput.Append(char charAsInt) |> ignore p.WaitForExit() log.Trace(sbOutput.ToString()) // it is fine that the logging occurs after the external tool has done its job - with e3 -> handleExceptionMessage log e3 + with e3 -> Logging.handleExceptionMessage log e3 None // If neither parsing, nor external executable tool search led to success, just return the error message | None -> - handleExceptionMessage log e2 + Logging.handleExceptionMessage log e2 None \ No newline at end of file diff --git a/src/ArcCommander/APIs/GitAPI.fs b/src/ArcCommander/APIs/GitAPI.fs index 995686a..eb6b518 100644 --- a/src/ArcCommander/APIs/GitAPI.fs +++ b/src/ArcCommander/APIs/GitAPI.fs @@ -4,7 +4,7 @@ open ArcCommander open ArgumentProcessing open Fake.IO open System.IO - +open arcIO.NET module GitAPI = @@ -28,7 +28,9 @@ module GitAPI = let repoDir = GeneralConfiguration.getWorkDirectory arcConfiguration let remoteAddress = getFieldValueByName "RepositoryAddress" gitArgs - + + let merge = containsFlag "Merge" gitArgs + let branch = match tryGetFieldValueByName "BranchName" gitArgs with | Some branchName -> $" -b {branchName}" @@ -40,7 +42,7 @@ module GitAPI = else "" - if System.IO.Directory.GetFileSystemEntries repoDir |> Array.isEmpty then + if merge then log.Trace("Downloading into current folder.") executeGitCommand repoDir $"clone {lfsConfig} {remoteAddress}{branch} ." |> ignore else @@ -113,7 +115,7 @@ module GitAPI = allFilesPlusSizes |> List.iter (fun (file,size) -> - /// Track files larger than the git lfs threshold with git lfs. If no threshold is set, track no files with git lfs + // Track files larger than the git lfs threshold with git lfs. If no threshold is set, track no files with git lfs match gitLfsThreshold with | Some thr when size > thr -> trackWithLFS file | _ -> trackWithAdd file diff --git a/src/ArcCommander/APIs/InvestigationAPI.fs b/src/ArcCommander/APIs/InvestigationAPI.fs index c9927ab..357dd41 100644 --- a/src/ArcCommander/APIs/InvestigationAPI.fs +++ b/src/ArcCommander/APIs/InvestigationAPI.fs @@ -5,7 +5,7 @@ open ArcCommander.ArgumentProcessing open ISADotNet open ISADotNet.XLSX - +open arcIO.NET /// ArcCommander Investigation API functions that get executed by the investigation focused subcommand verbs. module InvestigationAPI = @@ -66,7 +66,7 @@ module InvestigationAPI = let originalInvestigation = Investigation.fromFile investigationFilePath - API.Investigation.update updateOption originalInvestigation investigation + API.Investigation.updateBy updateOption originalInvestigation investigation |> Investigation.toFile investigationFilePath /// Opens the existing investigation info in the ARC with the text editor set in globalArgs. @@ -87,7 +87,7 @@ module InvestigationAPI = (Investigation.InvestigationInfo.fromRows 1 >> fun (_,_,_,item) -> Investigation.fromParts item [] [] [] [] []) investigation - API.Investigation.update API.Update.UpdateAllAppendLists investigation editedInvestigation + API.Investigation.updateBy API.Update.UpdateAllAppendLists investigation editedInvestigation |> Investigation.toFile investigationFilePath /// Deletes the existing investigation file in the ARC if the given identifier matches the identifier set in the investigation file. diff --git a/src/ArcCommander/APIs/RemoteAccessAPI.fs b/src/ArcCommander/APIs/RemoteAccessAPI.fs index 9384abb..8d15aa8 100644 --- a/src/ArcCommander/APIs/RemoteAccessAPI.fs +++ b/src/ArcCommander/APIs/RemoteAccessAPI.fs @@ -2,7 +2,7 @@ open ArcCommander open ArcCommander.ArgumentProcessing - +open arcIO.NET module RemoteAccessAPI = diff --git a/src/ArcCommander/APIs/StudyAPI.fs b/src/ArcCommander/APIs/StudyAPI.fs index 4a0aee3..c66c11d 100644 --- a/src/ArcCommander/APIs/StudyAPI.fs +++ b/src/ArcCommander/APIs/StudyAPI.fs @@ -7,6 +7,7 @@ open System open System.IO open ISADotNet open ISADotNet.XLSX +open arcIO.NET /// ArcCommander Study API functions that get executed by the study focused subcommand verbs. module StudyAPI = @@ -333,25 +334,14 @@ module StudyAPI = let log = Logging.createLogger "StudyShowLog" log.Info("Start Study Show") - + + let arcDir = GeneralConfiguration.getWorkDirectory arcConfiguration let identifier = getFieldValueByName "Identifier" studyArgs + let study = Study.readByIdentifier arcDir identifier - let investigationFilePath = IsaModelConfiguration.tryGetInvestigationFilePath arcConfiguration |> Option.get - - let investigation = Investigation.fromFile investigationFilePath - - match investigation.Studies with - | Some studies -> - match API.Study.tryGetByIdentifier identifier studies with - | Some study -> - study - |> Prompt.serializeXSLXWriterOutput Study.StudyInfo.toRows - |> log.Debug - | None -> - log.Error($"Study with the identifier {identifier} does not exist in the investigation file.") - () - | None -> - log.Error("The investigation does not contain any studies.") + study + |> Prompt.serializeXSLXWriterOutput Study.StudyInfo.toRows + |> log.Debug /// Lists all study identifiers registered in this ARC's investigation file. @@ -359,47 +349,9 @@ module StudyAPI = let log = Logging.createLogger "StudyListLog" - log.Info("Start Study List") + let arcDir = GeneralConfiguration.getWorkDirectory arcConfiguration - let investigationFilePath = IsaModelConfiguration.tryGetInvestigationFilePath arcConfiguration |> Option.get - log.Debug($"InvestigationFile: {investigationFilePath}") - - let investigation = Investigation.fromFile investigationFilePath - - let studyFileIdentifiers = set (IsaModelConfiguration.findStudyIdentifiers arcConfiguration) - - let studyIdentifiers = - investigation.Studies - |> Option.defaultValue [] - |> List.choose (fun s -> - match s.Identifier with - | None | Some "" -> - log.Warn("Study does not have identifier") - None - | Some i -> Some i - ) - |> set - - let onlyRegistered = Set.difference studyIdentifiers studyFileIdentifiers - let onlyInitialized = Set.difference studyFileIdentifiers studyIdentifiers - let combined = Set.union studyIdentifiers studyFileIdentifiers - - if not onlyRegistered.IsEmpty then - log.Warn("The ARC contains following registered studies that have no associated file:") - onlyRegistered - |> Seq.iter ((sprintf "WARN: %s") >> log.Warn) - log.Info($"You can init the study file using \"arc s init\"") - - if not onlyInitialized.IsEmpty then - log.Warn("The ARC contains study files with the following identifiers not registered in the investigation:") - onlyInitialized - |> Seq.iter ((sprintf "WARN: %s") >> log.Warn) - log.Info($"You can register the study using \"arc s register\"") - - if combined.IsEmpty then - log.Error("The ARC does not contain any studies.") - - combined + Study.list arcDir |> Seq.iter (fun identifier -> log.Debug(sprintf "Study: %s" identifier) ) @@ -999,12 +951,10 @@ module StudyAPI = let name = getFieldValueByName "DesignType" designArgs let design = - DesignDescriptors.fromString + OntologyAnnotation.fromString name (getFieldValueByName "TypeTermAccessionNumber" designArgs) - (getFieldValueByName "TypeTermSourceREF" designArgs) - - [] + (getFieldValueByName "TypeTermSourceREF" designArgs) let investigationFilePath = IsaModelConfiguration.tryGetInvestigationFilePath arcConfiguration |> Option.get @@ -1111,11 +1061,10 @@ module StudyAPI = let name = getFieldValueByName "DesignType" designArgs let design = - DesignDescriptors.fromString + OntologyAnnotation.fromString name (getFieldValueByName "TypeTermAccessionNumber" designArgs) (getFieldValueByName "TypeTermSourceREF" designArgs) - [] let studyIdentifier = getFieldValueByName "StudyIdentifier" designArgs diff --git a/src/ArcCommander/ArcCommander.fsproj b/src/ArcCommander/ArcCommander.fsproj index 9e6b3f6..84d2467 100644 --- a/src/ArcCommander/ArcCommander.fsproj +++ b/src/ArcCommander/ArcCommander.fsproj @@ -18,19 +18,20 @@ https://github.com/nfdi4plants/arcCommander/blob/developer/LICENSE https://github.com/nfdi4plants/arcCommander/blob/developer/RELEASE_NOTES.md arc - - + + - + + @@ -54,22 +55,31 @@ + + + + + + + PreserveNewest + + + - + - + + - - - - + + + + + - - - - - + + \ No newline at end of file diff --git a/src/ArcCommander/ArcConfiguration.fs b/src/ArcCommander/ArcConfiguration.fs index 934b26b..b328f60 100644 --- a/src/ArcCommander/ArcConfiguration.fs +++ b/src/ArcCommander/ArcConfiguration.fs @@ -2,6 +2,7 @@ open System.IO open IniData +open arcIO.NET /// Contains settings about the arc type ArcConfiguration = diff --git a/src/ArcCommander/ArcConversion.fs b/src/ArcCommander/ArcConversion.fs new file mode 100644 index 0000000..1ca194a --- /dev/null +++ b/src/ArcCommander/ArcConversion.fs @@ -0,0 +1,140 @@ +namespace ArcCommander + +open Logging +open ISADotNet +open ArcCommander.ArgumentProcessing + +open System +open System.IO +open System.Diagnostics +open Argu +open JsonDSL +open arcIO.NET +open arcIO.NET.Converter +open ISADotNet.QueryModel +open FsSpreadsheet.DSL +open FsSpreadsheet.ExcelIO +open FSharp.Data +open Octokit + +/// Functions for trying to run external tools, given the command line arguments can not be parsed. +module ArcConversion = + + let getDll (repoOwner : string) (repoName : string) (dllname : string) = + + let client = new GitHubClient(new ProductHeaderValue("ArcCommander")); + + let releases = client.Repository.Release.GetAll(repoOwner, repoName); + let latest = releases.Result.[0] + let asset = + latest.Assets + |> Seq.find (fun r -> r.Name = dllname) + match Http.Request(asset.BrowserDownloadUrl).Body with + | HttpResponseBody.Text s -> failwithf "no dll" + | HttpResponseBody.Binary b -> b + + let callMethodOfAssembly (typeName : string) (methodName : string) (assembly : System.Reflection.Assembly) = + let t = assembly.GetType(typeName) + let m = t.GetMethod(methodName) + m.Invoke(null,[||]) + + + let getISA (studyIdentifier : string option) (assayIdentifier : string option) arcDir : QInvestigation*QStudy*QAssay= + let i = Investigation.fromArcFolder arcDir + let s = + let s = + match studyIdentifier with + | Option.Some si -> i.Studies.Value |> List.find (fun s -> s.Identifier.Value = si) + | None -> i.Studies.Value.Head + let ps = + (s.ProcessSequence |> Option.defaultValue []) + @ + (s.Assays |> Option.defaultValue [] |> List.collect (fun a -> a.ProcessSequence |> Option.defaultValue [])) + {s with ProcessSequence = Option.Some ps} + let a = + match assayIdentifier with + | Option.Some ai -> s.Assays.Value |> List.find (fun a -> a.FileName.Value = Assay.nameToFileName ai) + | None -> s.Assays.Value.Head + + QInvestigation.fromInvestigation(i), + QStudy.fromStudy(s), + QAssay.fromAssay(a,[]) + + let prompt (msg:string) = + System.Console.Write(msg) + System.Console.ReadLine().Trim() + |> function | "" -> None | s -> Option.Some s + |> Option.map (fun s -> s.Replace ("\"","\\\"")) + + let rec promptYesNo msg = + match prompt (sprintf "%s [Yn]: " msg) with + | Option.Some "Y" | Option.Some "y" -> true + | Option.Some "N" | Option.Some "n" -> false + | _ -> System.Console.WriteLine("Sorry, invalid answer"); promptYesNo msg + + let handleTransformations arcDir namePrefix (messages : exn list) = + let i = Investigation.fromArcFolder arcDir + let s = i.Studies.Value.Head + let transformations = + messages + |> ISADotNet.QueryModel.ErrorHandling.getStudyformations namePrefix + |> List.distinct + let updatedStudy = + transformations + |> List.fold (fun s transformation -> transformation.Transform s) s + let updatedArc = + i + |> API.Investigation.mapStudies + (API.Study.updateByIdentifier API.Update.UpdateAll updatedStudy) + |> API.Investigation.update + Study.overWrite arcDir updatedStudy + Investigation.overWrite arcDir updatedArc + + let writeMessages (arcDir : string) (messages : exn list) = + let messagesOutPath = Path.Combine(arcDir,".arc/OutputMessages.txt") + messages + |> List.map (fun m -> m.ToString()) + |> List.toArray + |> Array.distinct + |> fun messages -> + File.WriteAllLines(messagesOutPath,messages) + + let handleXLSX (i : QInvestigation) (s : QStudy) (a : QAssay) arcDir converterName (f : arcIO.NET.Converter.ARCconverter) = + let outPath = Path.Combine([|arcDir;".arc";$"{converterName}.xlsx"|]) + match f.ConvertXLSX(i,s,a) with + | Some (workbook,messages) -> + let wb = workbook.Parse() + wb.ToFile(outPath) + Ok(messages |> List.choose (fun m -> m.TryException())) + | NoneOptional messages | NoneRequired messages -> + Error(messages |> List.choose (fun m -> m.TryException())) + + let handleCSV (i : QInvestigation) (s : QStudy) (a : QAssay) arcDir converterName (f : arcIO.NET.Converter.ARCconverter) = + let outPath = Path.Combine([|arcDir;".arc";$"{converterName}.csv"|]) + match f.ConvertCSV(i,s,a) with + | Some (workbook,messages) -> + let wb = workbook.Parse() + FsSpreadsheet.CsvIO.Writer.toFile(outPath,wb,Separator = ',') + Ok(messages |> List.choose (fun m -> m.TryException())) + | NoneOptional messages | NoneRequired messages -> + Error(messages |> List.choose (fun m -> m.TryException())) + + let handleTSV (i : QInvestigation) (s : QStudy) (a : QAssay) arcDir converterName (f : arcIO.NET.Converter.ARCconverter) = + let outPath = Path.Combine([|arcDir;".arc";$"{converterName}.csv"|]) + match f.ConvertCSV(i,s,a) with + | Some (workbook,messages) -> + let wb = workbook.Parse() + FsSpreadsheet.CsvIO.Writer.toFile(outPath,wb,Separator = '\t') + Ok(messages |> List.choose (fun m -> m.TryException())) + | NoneOptional messages | NoneRequired messages -> + Error(messages |> List.choose (fun m -> m.TryException())) + + let handleJSON (i : QInvestigation) (s : QStudy) (a : QAssay) arcDir converterName (f : arcIO.NET.Converter.ARCconverter) = + let outPath = Path.Combine([|arcDir;".arc";$"{converterName}.json"|]) + match f.ConvertJsn(i,s,a) with + | JEntity.Some (node,messages) -> + let s = node.ToJsonString() + File.WriteAllText(outPath,s) + Ok(messages |> List.map (fun m -> m.AsException())) + | JEntity.NoneOptional messages | JEntity.NoneRequired messages -> + Error(messages |> List.map (fun m -> m.AsException())) \ No newline at end of file diff --git a/src/ArcCommander/ArgumentProcessing.fs b/src/ArcCommander/ArgumentProcessing.fs index ca92646..5f8dd95 100644 --- a/src/ArcCommander/ArgumentProcessing.fs +++ b/src/ArcCommander/ArgumentProcessing.fs @@ -8,7 +8,7 @@ open System.Diagnostics open System.Text open System.Text.Json open Argu - +open arcIO.NET /// Functions for processing arguments. module ArgumentProcessing = @@ -28,20 +28,23 @@ module ArgumentProcessing = Tooltip : string IsMandatory : bool IsFlag : bool + IsFileName : bool } - let createAnnotatedArgument arg tt mand isFlag = + let createAnnotatedArgument arg tt mand isFlag isFN = { Arg = arg Tooltip = tt IsMandatory = mand IsFlag = isFlag + IsFileName = isFN } + // classic forbidden symbols for file names in Windows (which also includes Linux/macOS) + let private forbiddenSymbols = [|'/'; '\\'; '"'; '>'; '<'; '?'; '='; '*'; '|'|] + /// Characters that must not occur in file names. let private forbiddenChars = - // classic forbidden symbols for file names in Windows (which also includes Linux/macOS) - let forbiddenSymbols = [|'/'; '\\'; '"'; '>'; '<'; '?'; '='; '*'; '|'|] let controlChars = Array.init 32 (fun i -> char i) Array.append controlChars forbiddenSymbols @@ -77,6 +80,12 @@ module ArgumentProcessing = log.Error $"Identifier/filename \"{str}\" is a reserved filename. Please choose another one." raise (Exception "") + /// Takes a string and checks if it is longer than 31 chars + let private checkForNameLength (str : string) = + let log = Logging.createLogger "ArgumentProcessingCheckForFileNameLength" + if seq str |> Seq.length |> (<) 31 then + log.Warn $"Identifier/filename \"{str}\" is longer than 31 characters, which might cause problems in excel sheets." + /// Returns true if the argument flag of name k was given by the user. let containsFlag k (arguments : Map) = let log = Logging.createLogger "ArgumentProcessingContainsFlagLog" @@ -144,7 +153,7 @@ module ArgumentProcessing = | [||] -> let toolTip = (FSharpValue.MakeUnion (unionCase, [||]) :?> 'T).Usage let value,isFlag = if Map.containsKey unionCase.Name m then Some Flag,true else None,true - unionCase.Name,createAnnotatedArgument value toolTip isMandatory isFlag + unionCase.Name,createAnnotatedArgument value toolTip isMandatory isFlag isFileAttribute | [|c|] when c.PropertyType.Name = "String" -> let toolTip = (FSharpValue.MakeUnion (unionCase, [|box ""|]) :?> 'T).Usage let value, isFlag = @@ -155,13 +164,14 @@ module ArgumentProcessing = if isFileAttribute then iterForbiddenChars str checkForReservedFns str + checkForNameLength str replaceSpace str else str Field adjustedStr |> Some, false | None -> None, false - unionCase.Name, createAnnotatedArgument value toolTip isMandatory isFlag + unionCase.Name, createAnnotatedArgument value toolTip isMandatory isFlag isFileAttribute | _ -> log.Fatal($"Cannot parse argument {unionCase.Name} because its parsing rules were not yet implemented.") raise (Exception("")) @@ -239,13 +249,20 @@ module ArgumentProcessing = elif arg.IsFlag then sprintf "Remove # below to set flag: %s" arg.Tooltip else sprintf "%s" arg.Tooltip + let fileComment = + $"""# FileName: The value of this argument will be used as a file or folder name. +# FileName: Please refrain from using the following characters: {forbiddenSymbols |> Seq.map string |> String.concat " "}. +# FileName: Please write a value of length at most 31 characters.""" let value = match arg.Arg with | Some (Flag) -> sprintf "%s" key | Some (Field v) -> sprintf "%s:%s" key v | None when arg.IsFlag -> sprintf "#%s" key | None -> sprintf "%s:" key - sprintf "#%s\n%s" comment value + if arg.IsFileName then + sprintf "#%s\n%s\n%s" comment fileComment value + else + sprintf "#%s\n%s" comment value ) |> Array.reduce (fun a b -> a + "\n\n" + b) |> sprintf "%s\n\n%s" header @@ -260,6 +277,7 @@ module ArgumentProcessing = if key.Contains "Identifier" then iterForbiddenChars trValu checkForReservedFns trValu + checkForNameLength trValu replaceSpace trValu else trValu match s.Split c with diff --git a/src/ArcCommander/Authentication.fs b/src/ArcCommander/Authentication.fs index d5e1492..f172652 100644 --- a/src/ArcCommander/Authentication.fs +++ b/src/ArcCommander/Authentication.fs @@ -1,7 +1,6 @@ namespace ArcCommander open IdentityModel.OidcClient; -open Microsoft.Net.Http.Server; open System; open System.Collections.Generic; open System.Diagnostics; @@ -11,18 +10,18 @@ open System.Text; open System.Text.Json open System.Text.Json.Serialization open System.Threading.Tasks; -open JWT.Builder -open JWT.Algorithms +//open JWT.Builder +//open JWT.Algorithms module Authentication = - let decodeResponse (response : string) = + //let decodeResponse (response : string) = - JwtBuilder.Create() - |> fun b -> b.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric - //|> fun b -> b.WithSecret(secret) - //|> fun b -> b.MustVerifySignature() - |> fun b -> b.Decode(response) + // JwtBuilder.Create() + // |> fun b -> b.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric + // //|> fun b -> b.WithSecret(secret) + // //|> fun b -> b.MustVerifySignature() + // |> fun b -> b.Decode(response) /// Fields returned by the token service type IdentityToken = @@ -49,9 +48,9 @@ module Authentication = static member ofJson (jsonString : string) = ISADotNet.JsonExtensions.fromString jsonString - static member ofJwt (jwtResponse : string) = - decodeResponse jwtResponse - |> IdentityToken.ofJson + //static member ofJwt (jwtResponse : string) = + // decodeResponse jwtResponse + // |> IdentityToken.ofJson /// Create a standard html site text with given string as body let fillHTML s = $"

{s}

" @@ -154,8 +153,8 @@ module Authentication = return result } - [] /// Try to get the token information from a token service specified in the arc configuration + [] let tryLogin (log : NLog.Logger) authority (arcConfiguration : ArcConfiguration) = log.Info("Initiate login protocol") @@ -172,8 +171,8 @@ module Authentication = module OAuth2 = - [] /// Try to get the token information from a token service specified in the arc configuration + [] let tryLogin (log : NLog.Logger) authority (arcConfiguration : ArcConfiguration) = raise (NotImplementedException("Login via OAuth2 authorization protocol is not yet implemented")) \ No newline at end of file diff --git a/src/ArcCommander/CLIArguments/ArcArgs.fs b/src/ArcCommander/CLIArguments/ArcArgs.fs index 23a4619..ba407a3 100644 --- a/src/ArcCommander/CLIArguments/ArcArgs.fs +++ b/src/ArcCommander/CLIArguments/ArcArgs.fs @@ -1,8 +1,24 @@ namespace ArcCommander.CLIArguments /// ------------ TOP LEVEL ------------ /// + +open ArcCommander open Argu +open ArgumentProcessing + +type ArcConvertArgs = + + | [][][] Target of target : string + | [][][] StudyIdentifier of study_identifier : string + | [][][] AssayIdentifier of assay_identifier : string + interface IArgParserTemplate with + member this.Usage = + match this with + | Target _ -> "Target format to which arc should be exported." + | StudyIdentifier _ -> "Identifier of the study to be exported" + | AssayIdentifier _ -> "Identifier of the assay to be exported" + type ArcInitArgs = | [] Owner of owner : string @@ -18,7 +34,7 @@ type ArcInitArgs = match this with | Owner _ -> "Owner of the ARC" | Branch _ -> "Name of the git branch to be created" - | RepositoryAddress _ -> "Github address" + | RepositoryAddress _ -> "Git repository address" | EditorPath _ -> "The path leading to the editor used for text prompts (Default in Windows is Notepad; Default in Unix systems is Nano)" | GitLFSByteThreshold _ -> "The git LFS file size threshold in bytes. File larger than this threshold will be tracked by git LFS (Default Value is 150000000 Bytes ~ 150 MB)." | Gitignore _ -> "Use this flag if you want a default .gitignore to be added to the initialized repo" @@ -56,6 +72,7 @@ type ArcGetArgs = | [][][] RepositoryAddress of repository_address:string | [][] BranchName of branch_name:string | [][] NoLFS + | [][] Merge interface IArgParserTemplate with member this.Usage = @@ -63,3 +80,12 @@ type ArcGetArgs = | RepositoryAddress _ -> "Git remote address from which to pull the ARC" | BranchName _ -> "Branch of the remote address which should be used. If none is given, uses \"main\"" | NoLFS _ -> "Does download only the pointers of LFS files, not the file content itself. Ideal for when you're only interested in the experimental metadata, not the data itself." + | Merge _ -> "Merges the repository into the current folder. Fails, if the current folder isn't empty." + +type ArcServerArgs = + | [][] Port of port_address : string + + interface IArgParserTemplate with + member this.Usage = + match this with + | Port _ -> "" \ No newline at end of file diff --git a/src/ArcCommander/CLIArguments/AssayArgs.fs b/src/ArcCommander/CLIArguments/AssayArgs.fs index 0b8a45e..ad93f80 100644 --- a/src/ArcCommander/CLIArguments/AssayArgs.fs +++ b/src/ArcCommander/CLIArguments/AssayArgs.fs @@ -68,8 +68,8 @@ type AssayUpdateArgs = /// CLI arguments for interactively editing existing assay metadata. type AssayEditArgs = - | [][][] StudyIdentifier of study_identifier : string - | [][][][] AssayIdentifier of assay_identifier : string + | [][][] StudyIdentifier of study_identifier : string + | [][][][] AssayIdentifier of assay_identifier : string interface IArgParserTemplate with member this.Usage = diff --git a/src/ArcCommander/CLIArguments/InvestigationArgs.fs b/src/ArcCommander/CLIArguments/InvestigationArgs.fs index 8b7ca1d..f531470 100644 --- a/src/ArcCommander/CLIArguments/InvestigationArgs.fs +++ b/src/ArcCommander/CLIArguments/InvestigationArgs.fs @@ -1,13 +1,14 @@ namespace ArcCommander.CLIArguments open Argu +open ArcCommander.ArgumentProcessing /// CLI arguments for creating a new investigation file for the arc // in the case of investigations 'empty' does not mean empty file but rather an // investigation without studies/assays. To reflect the need for metadata here, // this command is called `create` instead of `init` type InvestigationCreateArgs = - | [][][] Identifier of investigation_identifier:string + | [][][][] Identifier of investigation_identifier:string | [] Title of title:string | [] Description of description:string | [] SubmissionDate of submission_date:string @@ -24,7 +25,7 @@ type InvestigationCreateArgs = /// CLI arguments updating the arc's existing investigation file type InvestigationUpdateArgs = - | [][][] Identifier of investigation_identifier:string + | [][][][] Identifier of investigation_identifier:string | [] Title of title:string | [] Description of description:string | [] SubmissionDate of submission_date:string diff --git a/src/ArcCommander/Commands/ArcCommand.fs b/src/ArcCommander/Commands/ArcCommand.fs index 132ba55..ab4ffb3 100644 --- a/src/ArcCommander/Commands/ArcCommand.fs +++ b/src/ArcCommander/Commands/ArcCommand.fs @@ -11,8 +11,10 @@ type ArcCommand = ///Commands | [] Init of init_args : ParseResults | [] Export of export_args : ParseResults + | [] Convert of convert_args : ParseResults | [] Sync of sync_args : ParseResults | [] Get of get_args : ParseResults + | [] Server of server_args : ParseResults | [][] Update | [][] Version ///Subcommands @@ -30,6 +32,7 @@ type ArcCommand = | Init _ -> "Initialize basic folder structure" | Update _ -> "Update items in the arc against each other" | Export _ -> "Exports the full arc to a json object" + | Convert _ -> "Converts the arc to a target format." | Sync _ -> "Syncronize the ARC with its upstream repository. Commits changes made in the ARC. If a remote is set or is given, also pulls from there and pushes all previously made commits." | Get _ -> "Download an ARC from a remote repository (e.g. from gitlab)" | RemoteAccess _ -> "Subcommands for handling access functionality to remote repositories" @@ -37,4 +40,5 @@ type ArcCommand = | Study _ -> "Study functions" | Assay _ -> "Assay functions" | Configuration _ -> "Configuration editing" - | Version _ -> "Get the ArcCommander's current version" \ No newline at end of file + | Version _ -> "Get the ArcCommander's current version" + | Server _ -> "Start the ArcCommander as a local server" \ No newline at end of file diff --git a/src/ArcCommander/GitHelper.fs b/src/ArcCommander/GitHelper.fs index 4c98a6d..6a0140b 100644 --- a/src/ArcCommander/GitHelper.fs +++ b/src/ArcCommander/GitHelper.fs @@ -3,6 +3,7 @@ open System.Diagnostics open System.Runtime.InteropServices open System.IO +open arcIO.NET module GitHelper = diff --git a/src/ArcCommander/IniData.fs b/src/ArcCommander/IniData.fs index 8683cfa..fa19886 100644 --- a/src/ArcCommander/IniData.fs +++ b/src/ArcCommander/IniData.fs @@ -6,6 +6,7 @@ open System.Runtime.InteropServices open IniParser open IniParser.Model +open arcIO.NET type OS = | Windows diff --git a/src/ArcCommander/Logging.fs b/src/ArcCommander/Logging.fs index da77324..5aa5cd8 100644 --- a/src/ArcCommander/Logging.fs +++ b/src/ArcCommander/Logging.fs @@ -81,36 +81,6 @@ module Logging = // activate config for logger LogManager.Configuration <- config - /// Creates a new logger with the given name. Configuration details are obtained from the generateConfig function. - let createLogger (loggerName : string) = - - // new instance of "Logger" with activated config - let logger = LogManager.GetLogger(loggerName) - - logger - - /// Takes a logger and an exception and separates usage and error messages. Usage messages will be printed into the console while error messages will be logged. - let handleExceptionMessage (log : NLog.Logger) (exn : Exception) = - // separate usage message (Argu) and error messages. Error messages shall be logged, usage messages shall not, empty error message shall not appear at all - let isUsageMessage = exn.Message.Contains("USAGE") || exn.Message.Contains("SUBCOMMANDS") - let isErrorMessage = exn.Message.Contains("ERROR") - let isEmptyMessage = exn.Message = "" - match isUsageMessage, isErrorMessage, isEmptyMessage with - | true,true,false -> // exception message contains usage AND error messages - let eMsg, uMsg = - exn.Message.Split(Environment.NewLine) // '\n' leads to parsing problems - |> fun arr -> - arr |> Array.find (fun t -> t.Contains("ERROR")), - arr |> Array.filter (fun t -> t.Contains("ERROR") |> not) |> String.concat "\n" // Argu usage instruction shall not be logged as error - log.Error(eMsg) - printfn "%s" uMsg - | true,false,false -> printfn "%s" exn.Message // exception message contains usage message but NO error message - | false,false,true -> () // empty error message - | _ -> log.Error(exn) // everything else will be a non-empty error message - - /// Checks if a message (string) is empty and if it is not, applies a logging function to it. - let checkNonLog s (logging : string -> unit) = if s <> "" then logging s - /// Deletes unwanted new lines at the end of an output. let rec reviseOutput (output : string) = if output = null then "" diff --git a/src/ArcCommander/Program.fs b/src/ArcCommander/Program.fs index bd0533a..80c5e0e 100644 --- a/src/ArcCommander/Program.fs +++ b/src/ArcCommander/Program.fs @@ -13,6 +13,7 @@ open System.IO open System.Text open System.Diagnostics open Argu +open arcIO.NET /// Runs the given command with the given arguments and configuration. If mandatory arguments are missing, or the "forceEditor" flag is set, opens a prompt asking for additional input. let processCommand (arcConfiguration : ArcConfiguration) commandF (r : ParseResults<'T>) = @@ -214,6 +215,8 @@ let handleCommand arcConfiguration command = // Verbs | Init r -> processCommand arcConfiguration ArcAPI.init r | Export r -> processCommand arcConfiguration ArcAPI.export r + | Convert r -> processCommand arcConfiguration ArcAPI.convert r + | Server r -> processCommand arcConfiguration Server.start r | Update -> processCommandWithoutArgs arcConfiguration ArcAPI.update | Version -> processCommandWithoutArgs arcConfiguration ArcAPI.version // Git Verbs diff --git a/src/ArcCommander/Server.fs b/src/ArcCommander/Server.fs new file mode 100644 index 0000000..283d084 --- /dev/null +++ b/src/ArcCommander/Server.fs @@ -0,0 +1,109 @@ +namespace ArcCommander + +open System.IO +open Microsoft.AspNetCore.Builder +open Microsoft.AspNetCore.Hosting +open Microsoft.Extensions.Hosting +open Microsoft.Extensions.DependencyInjection +open Giraffe +open ArcCommander.ArgumentProcessing +open Microsoft.AspNetCore.Http +open Microsoft.AspNetCore.Cors.Infrastructure +open Microsoft.AspNetCore.StaticFiles + +module Server = + + /// Test-API function + let numberHandler : HttpHandler = + let funFunction myInt = $"Your number is {myInt}!" + fun (next : HttpFunc) (ctx : HttpContext) -> + task { + let! number = ctx.BindJsonAsync() + let nextNumber = funFunction number + // das machen wir so! + return! json {| ``is this your number?`` = nextNumber |} next ctx + } + + /// API function for checking the application's version. + let versionHandler : HttpHandler = + fun (next : HttpFunc) (ctx : HttpContext) -> + task { + let ver = System.AssemblyVersionInformation.AssemblyVersion + return! json ver next ctx + } + + /// Endpoints + let webApp = + // TO DO: establish versioning for APIs: e.g. `localhost/api/v1/ping`, "v1" should be the ArcCommander's version + choose [ + GET >=> choose [ + route "/version" >=> versionHandler + route "/ping" >=> text "pong" + ] + POST >=> choose [ + route "/ping" >=> numberHandler + ] + subRoute "/v1" ( + subRoute "/arc" ( + choose [ + GET >=> route "/docs" >=> htmlView ArcApi.Docs.view + POST >=> choose [ + route "/get" >=> ArcAPIHandler.isaJsonToARCHandler + route "/init" >=> ArcAPIHandler.arcInitHandler + route "/import" >=> ArcAPIHandler.arcImportHandler + ] + ] + ) + ) + ] + + let corsPolicyName = "_myAllowSpecificOrigins" + + let corsPolicyConfig = + fun (b : CorsPolicyBuilder) -> + b + .AllowAnyHeader() + .AllowAnyMethod() + .AllowAnyOrigin() + |> ignore + + let configureApp (app : IApplicationBuilder) = + let provider = new FileExtensionContentTypeProvider() + provider.Mappings.Add(".yaml", "application/x-yaml") + app.UseStaticFiles( + let opt = new StaticFileOptions() + opt.ContentTypeProvider <- provider + opt + ) |> ignore + // Add Giraffe to the ASP.NET Core pipeline + app.UseCors(corsPolicyName) |> ignore + app.UseGiraffe webApp + + let configureServices (services : IServiceCollection) = + // Add Giraffe dependencies + services.AddCors(fun options -> options.AddPolicy(corsPolicyName, corsPolicyConfig)) |> ignore + services.AddGiraffe() |> ignore + + let start arcConfiguration (arcServerArgs : Map) = + + let port = + tryGetFieldValueByName "Port" arcServerArgs + |> Option.defaultValue "5000" + + // https://trustbit.tech/blog/2021/03/12/introduction-to-web-programming-in-f-sharp-with-giraffe-part-3 + // This only works because we added webroot folder to be included in .fsproj + /// returns folder of dll in bin/.. somethingsomething + let contentRoot = Directory.GetCurrentDirectory() + let webRoot = Path.Combine(contentRoot, "Server/WebRoot") + + Host.CreateDefaultBuilder() + .ConfigureWebHostDefaults( + fun webHostBuilder -> + webHostBuilder + .UseWebRoot(webRoot) + .UseUrls([|$"http://*:{port}"|]) + .Configure(configureApp) + .ConfigureServices(configureServices) + |> ignore) + .Build() + .Run() \ No newline at end of file diff --git a/src/ArcCommander/Server/ApiDocs/ArcApi.Docs.fs b/src/ArcCommander/Server/ApiDocs/ArcApi.Docs.fs new file mode 100644 index 0000000..a311113 --- /dev/null +++ b/src/ArcCommander/Server/ApiDocs/ArcApi.Docs.fs @@ -0,0 +1,3 @@ +module ArcApi.Docs + +let view = Docs.baseViews "IArcAPI_v1.yaml" \ No newline at end of file diff --git a/src/ArcCommander/Server/ApiDocs/BaseView.Docs.fs b/src/ArcCommander/Server/ApiDocs/BaseView.Docs.fs new file mode 100644 index 0000000..6e0896a --- /dev/null +++ b/src/ArcCommander/Server/ApiDocs/BaseView.Docs.fs @@ -0,0 +1,39 @@ +module Docs + +open Giraffe.ViewEngine + +let private head = + head [] [ + meta [_charset "utf-8"] + meta [_name "viewport"; _content "width=device-width, initial-scale=1"] + meta [_name "description"; _content "SwaggerUI"] + title [] [str "SwaggerUI"] + link [_rel "shortcut icon"; _type "image/png"; _href "https://raw.githubusercontent.com/nfdi4plants/Branding/master/icons/DataPLANT/favicons/favicon_bg_transparent.png" ] + link [_rel "stylesheet"; _href "https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui.css"] + ] + +let private js_binder (yamlFileName:string) = + sprintf """ + const url = new URL('./%s', window.location.origin) + window.onload = () => { + window.ui = SwaggerUIBundle({ + url: url.href, + dom_id: '#swagger-ui', + }); + }; + """ yamlFileName + +let private body (yamlFileName:string) = + body [] [ + div [_id "swagger-ui"] [] + script [_src "https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-bundle.js"; _crossorigin ""] [] + script [] [ + rawText (js_binder yamlFileName) + ] + ] + +let baseViews (yamlFileName:string) = + html [] [ + head + body yamlFileName + ] \ No newline at end of file diff --git a/src/ArcCommander/Server/ArcAPIHandler.fs b/src/ArcCommander/Server/ArcAPIHandler.fs new file mode 100644 index 0000000..6b07083 --- /dev/null +++ b/src/ArcCommander/Server/ArcAPIHandler.fs @@ -0,0 +1,78 @@ +module ArcAPIHandler + +open Giraffe +open Microsoft.AspNetCore.Http +open System +open System.IO +open System.IO.Compression +open ArcCommander +open ArcCommander.APIs +open ISADotNet + +/// +let isaJsonToARCHandler : HttpHandler = + fun (next : HttpFunc) (ctx : HttpContext) -> + // modified from: https://stackoverflow.com/questions/17232414/creating-a-zip-archive-in-memory-using-system-io-compression + task { + let isaJson = ctx.Request.Body + let ms = new MemoryStream() + let! _ = isaJson.CopyToAsync(ms) + let isaJsonBA = ms.ToArray() + + let getByteArray (fileName : string) (data : byte []) = + try + use ms = new MemoryStream() + ( + use archive = new ZipArchive(ms, ZipArchiveMode.Create) + let entry = archive.CreateEntry(fileName) + use entryStream = entry.Open() + use bw = new BinaryWriter(entryStream) + bw.Write(data) + ) + (ms.ToArray()) + with e -> failwithf "Cannot zip stream %s: %s" fileName e.Message + let res = getByteArray "arc.json" isaJsonBA + return! ctx.WriteBytesAsync res + } + +//type InitConfig = { +// path : string +//} + +let arcInitHandler : HttpHandler = + fun (next : HttpFunc) (ctx : HttpContext) -> + task { + let! config = ctx.BindJsonAsync<{|path : string|}>() + //let arcConfig = IniData.createDefault + //ArcAPI.init + + return! json config next ctx + } + +//type AlibiJson = { +// Alles : string +//} + +/// Gets an ISA-JSON string via POST request and returns a byte array of a zipped archive of an ARC created from it. +let arcImportHandler : HttpHandler = + fun (next : HttpFunc) (ctx : HttpContext) -> + task { + let! isaJsonString = ctx.BindJsonAsync() + + let tmpDir = Path.Combine(Path.GetTempPath(), "tmpArc") + let tmpZip = Path.Combine(Path.GetTempPath(), "tmpArc.zip") + + ISADotNet.Json.Investigation.fromString isaJsonString + |> fun i -> {i with Remarks = []} + |> arcIO.NET.Arc.importFromInvestigation tmpDir + + System.IO.Compression.ZipFile.CreateFromDirectory(tmpDir,tmpZip ) + + Directory.Delete(tmpDir, true) + + let byteArc : byte [] = File.ReadAllBytes tmpZip + + File.Delete tmpZip + + return! ctx.WriteBytesAsync byteArc + } \ No newline at end of file diff --git a/src/ArcCommander/Server/Version.fs b/src/ArcCommander/Server/Version.fs new file mode 100644 index 0000000..2801571 --- /dev/null +++ b/src/ArcCommander/Server/Version.fs @@ -0,0 +1,13 @@ +// Auto-Generated by FAKE; do not edit +namespace System +open System.Reflection + +[] +[] +[] +do () + +module internal AssemblyVersionInformation = + let [] AssemblyTitle = "ArcCommander" + let [] AssemblyVersion = "0.5.0" + let [] AssemblyMetadata_ReleaseDate = "12.04.2023" diff --git a/src/ArcCommander/Server/WebRoot/IArcAPI_v1.yaml b/src/ArcCommander/Server/WebRoot/IArcAPI_v1.yaml new file mode 100644 index 0000000..ef39aa3 --- /dev/null +++ b/src/ArcCommander/Server/WebRoot/IArcAPI_v1.yaml @@ -0,0 +1,80 @@ +openapi: 3.0.3 +info: + version: 0.0.1 + title: ARC API v1 + description: |- + ARC API docs description + email: info@nfdi4plants.org +servers: + - url: "http://localhost:5000" + description: "Local Test" +paths: + /ping: + get: + summary: "Test function to verify client server connection." + description: "This function is only used for testing connection. If client has connection to server this request will return `pong`." + operationId: GET_ping + responses: + 200: + description: "OK" + content: + text/plain: + schema: + type: string + examples: + Only_Result: + summary: This api must always return "pong". + value: "pong" + post: + summary: "Test function to verify client server connection." + description: "This function is only used for testing connection. If client has connection to server and requests an integer, this request will return it." + operationId: POST_ping + requestBody: + description: "Test POST API request." + content: + application/json: + schema: + type: integer + examples: + the_answer: + summary: any number + value: 42 + responses: + 200: + description: "OK" + content: + application/json: + schema: + type: object + properties: + "is this your number?": + type: string + examples: + the_answer: + value: + "is this your number?": "Your number is 42!" + + /v1/arc/get: + post: + summary: "Takes an ISA-JSON as byte stream and returns a byte stream, consisting of the corresponding ARC created from it as a ZIP archive." + description: | + Give an ISA-JSON as byte stream via Http Request. + The ArcCommander server as backend will process and create the resulting ARC out of it. The ARC gets compressed as a ZIP archive. + This ZIP archive is then returned as a byte stream again. + operationId: POST_v1/arc/get + requestBody: + description: | + A JSON file, consisting of ISA, in the form of a byte stream. + content: + "*/*": + schema: + type: string + format: byte + responses: + 200: + description: "OK" + content: + "*/*": + schema: + type: string + format: byte \ No newline at end of file diff --git a/src/ArcCommander/defaultGitignore b/src/ArcCommander/defaultGitignore new file mode 100644 index 0000000..7904a6b --- /dev/null +++ b/src/ArcCommander/defaultGitignore @@ -0,0 +1,83 @@ +# ----- macos rules ----- +# taken from https://github.com/github/gitignore/blob/main/Global/macOS.gitignore + + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + + + + +# ----- windows rules ----- +# taken from https://github.com/github/gitignore/blob/main/Global/Windows.gitignore + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + + + + + +# ----- linux rules ----- +# taken from https://github.com/github/gitignore/blob/main/Global/Linux.gitignore + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* \ No newline at end of file diff --git a/tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj b/tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj index d75b94a..9377398 100644 --- a/tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj +++ b/tests/ArcCommander.Tests.NetCore/ArcCommander.Tests.NetCore.fsproj @@ -19,12 +19,9 @@ - + - - - diff --git a/tests/ArcCommander.Tests.NetCore/ArcCommander/StudyTests.fs b/tests/ArcCommander.Tests.NetCore/ArcCommander/StudyTests.fs index b1ed2b7..7e34cce 100644 --- a/tests/ArcCommander.Tests.NetCore/ArcCommander/StudyTests.fs +++ b/tests/ArcCommander.Tests.NetCore/ArcCommander/StudyTests.fs @@ -196,7 +196,6 @@ let testStudyContacts = let studyBeforeChangingIt = ISADotNet.XLSX.Investigation.fromFile investigationToCopy |> API.Investigation.getStudies - |> Option.get |> API.Study.tryGetByIdentifier studyIdentifier |> Option.get