├── .gitignore ├── APLSource ├── NuGet │ ├── ⎕IO.apla │ ├── ⎕ML.apla │ ├── API │ │ ├── Add.aplf │ │ ├── Setup.aplf │ │ ├── Packages.aplf │ │ ├── Publish.aplf │ │ ├── Using.aplf │ │ ├── BinFolder.aplf │ │ └── Version.aplf │ ├── IsWin.aplf │ ├── Version.aplf │ ├── findfile.aplf │ ├── NativeFolder.aplf │ ├── Public.aplf │ ├── Publish.aplf │ ├── CmdPaths.aplf │ ├── BinFolder.aplf │ ├── CSProjXML.aplf │ ├── Packages.aplf │ ├── APLVersion.aplf │ ├── GetNamespaces.aplf │ ├── CopyNativeFiles.aplf │ ├── CMD.aplf │ ├── Setup.aplf │ ├── GetDotNetIDS.aplf │ ├── Add.aplf │ └── Using.aplf ├── Tests │ ├── ⎕IO.apla │ ├── ⎕ML.apla │ ├── parquet │ │ ├── userdata1.parquet │ │ ├── ReadColumns.aplf │ │ └── Read.aplf │ ├── test__clock.aplf │ ├── test__mailkit.aplf │ ├── test__humanizer.aplf │ ├── test__selenium.aplf │ ├── teardown_nuget.aplf │ ├── test__htmlsanitizer.aplf │ ├── test_clock.aplf │ ├── find_nuget_api.aplf │ ├── test_kafka_wip.aplf │ ├── test_humanizer.aplf │ ├── MkUniqueDir.aplf │ ├── nuget.dyalogtest │ ├── test.aplf │ ├── test_htmlsanitizer.aplf │ ├── setup_nuget.aplf │ ├── test_parquet.aplf │ ├── test_mailkit.aplf │ ├── setup_ResetTempDirs.aplf │ └── test_selenium.aplf └── Admin │ └── Make.aplf ├── .gitattributes ├── apl-package.json ├── cider.config ├── LICENSE ├── CITA.json5 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Dist 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/⎕IO.apla: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/⎕ML.apla: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /APLSource/Tests/⎕IO.apla: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /APLSource/Tests/⎕ML.apla: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Add.aplf: -------------------------------------------------------------------------------- 1 | Add←{##.Add ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Setup.aplf: -------------------------------------------------------------------------------- 1 | Setup←{##.Setup ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Packages.aplf: -------------------------------------------------------------------------------- 1 | Packages←{##.Packages ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Publish.aplf: -------------------------------------------------------------------------------- 1 | Publish←{##.Publish ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Using.aplf: -------------------------------------------------------------------------------- 1 | Using←{⍺←⊢ ⋄ ⍺ ##.Using ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/BinFolder.aplf: -------------------------------------------------------------------------------- 1 | BinFolder←{##.BinFolder ⍵} 2 | -------------------------------------------------------------------------------- /APLSource/NuGet/IsWin.aplf: -------------------------------------------------------------------------------- 1 | r←IsWin 2 | r←'win'≡APLVersion 1 3 | -------------------------------------------------------------------------------- /APLSource/NuGet/Version.aplf: -------------------------------------------------------------------------------- 1 | version←Version 2 | version←'0.2.6' 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.apl? linguist-language=APL 3 | -------------------------------------------------------------------------------- /APLSource/NuGet/API/Version.aplf: -------------------------------------------------------------------------------- 1 | version←Version 2 | version←##.Version 3 | -------------------------------------------------------------------------------- /APLSource/NuGet/findfile.aplf: -------------------------------------------------------------------------------- 1 | findfile←{{(1=≢⍵)/⊃⍵}⊃0 ⎕NINFO⍠1⊢⍵} ⍝ File name if exactly one found, else '' 2 | -------------------------------------------------------------------------------- /APLSource/Tests/parquet/userdata1.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dyalog/nuget/main/APLSource/Tests/parquet/userdata1.parquet -------------------------------------------------------------------------------- /APLSource/NuGet/NativeFolder.aplf: -------------------------------------------------------------------------------- 1 | r←NativeFolder project_dir;xml;target;RID;TFM 2 | (TFM RID)←GetDotNetIDS ⍬ 3 | r←project_dir,'/runtimes/',RID,'/native' 4 | -------------------------------------------------------------------------------- /APLSource/NuGet/Public.aplf: -------------------------------------------------------------------------------- 1 | r←Public 2 | r←'' 3 | r,←⊂'Add' 4 | r,←⊂'Packages' 5 | r,←⊂'Setup' 6 | r,←⊂'Using' 7 | r,←⊂'Version' 8 | r,←⊂'BinFolder' 9 | 10 | -------------------------------------------------------------------------------- /APLSource/NuGet/Publish.aplf: -------------------------------------------------------------------------------- 1 | {r}←Publish project_dir;z 2 | z←⎕CMD CmdPaths'dotnet publish ',project_dir,' -o ',project_dir,'/published' 3 | r←CopyNativeFiles project_dir 4 | -------------------------------------------------------------------------------- /APLSource/NuGet/CmdPaths.aplf: -------------------------------------------------------------------------------- 1 | r←CmdPaths p 2 | ⍝ Fix up an argument to ⎕SH for the target platform 3 | 4 | :If IsWin 5 | r←('/'⎕R'\\')p 6 | :Else 7 | r←('\\'⎕R'/')p 8 | :EndIf 9 | -------------------------------------------------------------------------------- /APLSource/Tests/test__clock.aplf: -------------------------------------------------------------------------------- 1 | r←test__clock nul 2 | ⍝ a cover function for DTest to call the actual test function "test_***" through "test" (which setup NuGet for that specific test) 3 | r←test 6↓1⊃⎕SI -------------------------------------------------------------------------------- /APLSource/Tests/test__mailkit.aplf: -------------------------------------------------------------------------------- 1 | r←test__mailkit nul 2 | ⍝ a cover function for DTest to call the actual test function "test_***" through "test" (which setup NuGet for that specific test) 3 | r←test 6↓1⊃⎕SI -------------------------------------------------------------------------------- /APLSource/Tests/test__humanizer.aplf: -------------------------------------------------------------------------------- 1 | r←test__humanizer nul 2 | ⍝ a cover function for DTest to call the actual test function "test_***" through "test" (which setup NuGet for that specific test) 3 | r←test 6↓1⊃⎕SI -------------------------------------------------------------------------------- /APLSource/Tests/test__selenium.aplf: -------------------------------------------------------------------------------- 1 | r←test__selenium nul 2 | ⍝ a cover function for DTest to call the actual test function "test_***" through "test" (which setup NuGet for that specific test) 3 | r←test 6↓1⊃⎕SI -------------------------------------------------------------------------------- /APLSource/Tests/teardown_nuget.aplf: -------------------------------------------------------------------------------- 1 | {r}←teardown_nuget nul 2 | r←'' 3 | ⍝ 2⎕ndelete tmpDir 4 | ⍝start←{⎕SHELL⍠'Shell' ('CMD.EXE' '/C')⊢'start "" ',⊃8374⌶⍵} 5 | ⍝ start ((⊃160⌶'DYALOG'),'\dyalog.exe') 'MAXWS=1G' -------------------------------------------------------------------------------- /APLSource/Tests/test__htmlsanitizer.aplf: -------------------------------------------------------------------------------- 1 | r←test__htmlsanitizer nul 2 | ⍝ a cover function for DTest to call the actual test function "test_***" through "test" (which setup NuGet for that specific test) 3 | r←test 6↓1⊃⎕SI -------------------------------------------------------------------------------- /APLSource/NuGet/BinFolder.aplf: -------------------------------------------------------------------------------- 1 | r←BinFolder project_dir;xml;target 2 | xml←⊃CSProjXML project_dir 3 | target←⊃xml[xml[;2]⍳⊂'TargetFramework';3] 4 | r←({⊃(⎕NEXISTS ⍵)/⍵}(project_dir,'/bin')∘,¨'/Debug' '/Release'),'/',target 5 | -------------------------------------------------------------------------------- /APLSource/NuGet/CSProjXML.aplf: -------------------------------------------------------------------------------- 1 | (xml filename)←CSProjXML project_dir;xml;a;pfolder 2 | filename←findfile project_dir,'/*.csproj' 3 | (project_dir,' does not contain exactly one .csproj file')⎕SIGNAL(0=≢filename)/11 4 | xml←⎕XML⊃⎕NGET filename 5 | -------------------------------------------------------------------------------- /APLSource/Tests/test_clock.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_clock project_dir;⎕USING 2 | r←'' ⍝ no checks here - error will be caught when executed throught DTest or in CITA 3 | NuGet.Add project_dir 'Clock/1.0.3' 4 | ⎕USING←NuGet.Using project_dir 5 | 'The time is: ',⍕Clock.UtcNow 6 | -------------------------------------------------------------------------------- /APLSource/Tests/find_nuget_api.aplf: -------------------------------------------------------------------------------- 1 | ref←find_nuget_api;name 2 | ⍝ Prioritised search for a NuGet API 3 | 4 | :For name :In '##.APLSource' '##.NuGet' '#.NuGet' '⎕SE.Dyalog.NuGet' 5 | :If 9=⎕NC name 6 | →0⊣ref←⍎name 7 | :EndIf 8 | :EndFor 9 | 10 | 'Unable to locate NuGet API' ⎕SIGNAL 6 11 | -------------------------------------------------------------------------------- /APLSource/NuGet/Packages.aplf: -------------------------------------------------------------------------------- 1 | pkgs←Packages project_dir ;xml;filename;refs 2 | ⍝ Retrieve Package References from the project folder 3 | xml←⊃CSProjXML project_dir 4 | 5 | :If 0=≢refs←xml[⍸xml[;2]∊⊂'PackageReference';4] 6 | pkgs←⍬ 7 | :Else 8 | pkgs←{0=≢⍵:'' '' ⋄ ⍵[⍵[;1]⍳'Include' 'Version';2]}¨refs 9 | :EndIf 10 | -------------------------------------------------------------------------------- /APLSource/Tests/test_kafka_wip.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_kafka_wip project_dir;using;prefixes;path;drvs;drv;p;⎕using 2 | r←'This example doesn''t work yet, please try again later' 3 | →0 4 | 5 | ⎕SE.Link.Create'DKaf' 'c:\devt\DKaf' 6 | 7 | p←⎕NEW DKaf.Producer(⊂'localhost:9092') 8 | p.Produce('dyalog' 'mykey' 'This should be a utf8 string') 9 | -------------------------------------------------------------------------------- /APLSource/Tests/test_humanizer.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_humanizer project_dir;⎕USING;dt 2 | r←'' ⍝ no checks here - error will be caught when executed throught DTest or in CITA 3 | NuGet.Add project_dir'Humanizer.Core' 4 | ⎕USING←'(includePrimary: 0)'NuGet.Using project_dir 5 | dt←System.DateTime.Parse⊂'31/10/1962' 6 | ⎕←dt.Humanize ⎕NULL(System.DateTime.Now)⎕NULL 7 | -------------------------------------------------------------------------------- /APLSource/Tests/MkUniqueDir.aplf: -------------------------------------------------------------------------------- 1 | {r}←MkUniqueDir w 2 | ⍝ emulates ⎕MKDIR⍠'Unique' in versions < 20 3 | 4 | :If 20≤2 1⊃'.'⎕VFI 2⊃'#'⎕WG'APLVersion' 5 | ⍝ :If 20≤APLVersion 2 ⍝ neater, but not possible, as this tool is needed before NuGet is loaded 6 | r←⎕MKDIR(⍠'Unique' 1)w 7 | :Else 8 | r←w 9 | :While ⎕NEXISTS r 10 | r,←(⎕A,⎕D)[?36] 11 | :EndWhile 12 | :EndIf 13 | -------------------------------------------------------------------------------- /APLSource/Tests/parquet/ReadColumns.aplf: -------------------------------------------------------------------------------- 1 | ReadColumns←{ 2 | ⍝ ⍺ ←→ Parquet.NET RowGroupReader 3 | ⍝ ⍵ ←→ Parquet.NET Data Field 4 | ⍝ ← ←→ Simple array of data 5 | ct←⎕NEW System.Threading.CancellationToken 0 6 | cd←⍺.ReadColumnAsync ⍵ ct 7 | d←cd.Result.Data 8 | type←¯2↓⊃⌽'.'(≠⊆⊢)⍵.ToString 9 | 'DateTime'≡type:1 ⎕DT⊆d.(Year Month Day Hour Minute Second Millisecond) 10 | ↑d 11 | } 12 | -------------------------------------------------------------------------------- /APLSource/Admin/Make.aplf: -------------------------------------------------------------------------------- 1 | zipFilename←Make;cfg;noOf;parms 2 | cfg←⎕se.Tatin.ReadPackageConfigFile ##.CiderConfig.HOME 3 | noOf←⎕se.Tatin.CreateAPIfromCFG ##.NuGet cfg 4 | {⍵:.} 5≠noOf ⍝ Expected number of public API functions 5 | parms←⎕se.Tatin.CreateBuildParms ##.CiderConfig.HOME 6 | parms.version←##.NuGet.Version 7 | parms.targetPath←##.CiderConfig.HOME,'/',##.CiderConfig.CIDER.distributionFolder 8 | zipFilename←⎕se.Tatin.BuildPackage parms 9 | -------------------------------------------------------------------------------- /APLSource/NuGet/APLVersion.aplf: -------------------------------------------------------------------------------- 1 | R←APLVersion sel 2 | ⍝ returns elements of APLVersion specified by sel (see below) 3 | ⍝ passing any other than the supported value simply returns the full APLVersion string 4 | R←'.'⎕WG'APLVersion' 5 | :Select sel 6 | :Case 1 ⍝ sel=1: return leading 3 characters of lowercase platform name 7 | R←⎕C 3↑1⊃R 8 | :Case 2 ⍝ sel=2: return major version no. 9 | R←2 1⊃'.'⎕VFI 2⊃R 10 | :EndSelect 11 | -------------------------------------------------------------------------------- /APLSource/Tests/nuget.dyalogtest: -------------------------------------------------------------------------------- 1 | DyalogTest : 1.30 2 | ID : nuget 3 | Description: DTest for NuGet 4 | 5 | Setup : setup_nuget 6 | 7 | ⍝ test_kafka and test_parquet are not called - they are WIP currently 8 | ⍝ the "test__*" cover fns are created by setup_n uget 9 | Test : test__clock 10 | Test : test__htmlsanitizer 11 | Test : test__humanizer 12 | Test : test__mailkit 13 | Test : test__selenium 14 | 15 | Teardown: teardown_nuget -------------------------------------------------------------------------------- /APLSource/NuGet/GetNamespaces.aplf: -------------------------------------------------------------------------------- 1 | r←GetNamespaces name;⎕using;mine;assemblies 2 | ⍝ Return Namespaces which begin with name 3 | ⍝ Note that the namespaces must have been references to be loaded 4 | ⍝ (just setting ⎕USING is not enough) 5 | 6 | ⎕using←'System' 'System.Reflection' 7 | assemblies←AppDomain.CurrentDomain.GetAssemblies 8 | mine←name {(((≢⍺)↑¨⍕¨⍵)∊⊂⍺)/⍵} assemblies 9 | :If 0≠≢mine 10 | r←mine.GetExportedTypes.ToString 11 | :Else 12 | r←0⍴⊂'' 13 | :EndIf 14 | -------------------------------------------------------------------------------- /APLSource/NuGet/CopyNativeFiles.aplf: -------------------------------------------------------------------------------- 1 | {r}←CopyNativeFiles project_dir;target;native;n 2 | 3 | :If ⎕NEXISTS native←NativeFolder project_dir 4 | :If 0≠≢findfile (target←project_dir),'/*.deps.json' 5 | :OrIf 0≠≢findfile (target←project_dir,'/published'),'/*.deps.json' 6 | n←target ⎕NCOPY⍠('IfExists' 'Skip')('Wildcard' 1)⊢native,'/*' 7 | :Else 8 | 'Unable to locate target directory' ⎕SIGNAL 11 9 | :EndIf 10 | r←(⍕n),' new native files copied from ',native 11 | :Else 12 | r←'no native files to copy' 13 | :EndIf 14 | -------------------------------------------------------------------------------- /apl-package.json: -------------------------------------------------------------------------------- 1 | { 2 | api: "API", 3 | assets: "", 4 | description: "Use NuGet packages from Dyalog APL", 5 | documentation: "", 6 | exclude: "⎕IO.apla,⎕ML.apla", 7 | files: "", 8 | group: "dyalog", 9 | io: 1, 10 | license: "MIT", 11 | lx: "", 12 | maintainer: "support@dyalog.com", 13 | minimumAplVersion: "19.0", 14 | ml: 1, 15 | name: "NuGet", 16 | os_lin: 1, 17 | os_mac: 1, 18 | os_win: 1, 19 | project_url: "https://github.com/dyalog/nuget", 20 | source: "APLSource/NuGet", 21 | tags: "dotnet,nuget,packages", 22 | userCommandScript: "", 23 | version: "0.2.6", 24 | } 25 | -------------------------------------------------------------------------------- /cider.config: -------------------------------------------------------------------------------- 1 | { 2 | CIDER: { 3 | cider_version: "0.41.1", 4 | dependencies: { 5 | nuget: "", 6 | tatin: "", 7 | }, 8 | dependencies_dev: { 9 | tatin: "", 10 | }, 11 | distributionFolder: "Dist", 12 | init: "", 13 | make: "Admin.Make", 14 | parent: "#", 15 | projectSpace: "NuGet", 16 | project_url: "https://github.com/dyalog/nuget", 17 | source: "APLSource", 18 | tatinVars: "NuGet", 19 | tests: "", 20 | version: "0.2.6", 21 | }, 22 | LINK: { 23 | }, 24 | SYSVARS: { 25 | io: 1, 26 | ml: 1, 27 | }, 28 | USER: { 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /APLSource/NuGet/CMD.aplf: -------------------------------------------------------------------------------- 1 | r←CMD cmd;qdmx;⎕RL;tempFilename 2 | ⍝ Cover function for ⎕CMD. Deals with the fact that ⎕CMD behaves differently on Windows compared with Linux and Mac OS 3 | r←'' 4 | ⎕RL←⍬ 5 | tempFilename←(739⌶0),'/',⎕AN,'-',⍕100000+?10000000 6 | :Trap 11 7 | r←⎕CMD cmd,'>',tempFilename,' 2>&1' 8 | :If 0=≢r 9 | :If ⎕NEXISTS tempFilename 10 | r←⊃⎕NGET tempFilename 1 11 | :Else 12 | 'Something went wrong'⎕SIGNAL 11 13 | :EndIf 14 | :EndIf 15 | :Else 16 | qdmx←⎕DMX 17 | :If ⎕NEXISTS tempFilename 18 | r←⊃⎕NGET tempFilename 1 19 | :Else 20 | 3 ⎕NDELETE tempFilename 21 | qdmx.EM ⎕SIGNAL qdmx.EN 22 | :EndIf 23 | :EndTrap 24 | 3 ⎕NDELETE tempFilename 25 | ⍝Done 26 | -------------------------------------------------------------------------------- /APLSource/Tests/test.aplf: -------------------------------------------------------------------------------- 1 | {r}←test name;folder;NuGet;R;⎕USING 2 | ⍝ localizes ⎕USING just in case a test does not... 3 | r←'' 4 | :If 0=≢name 5 | ⎕←'The current test functions exist:' 6 | ⎕←{(1=+/¨'_'=⍵)/⍵}'t'⎕NL-3 7 | →0 8 | :EndIf 9 | :If 0=⎕NC'tmpDir' ⍝ is created in setup_nuget, may not available when used in the session... 10 | tmpDir←MkUniqueDir(739⌶0),'/NuGet_' 11 | :EndIf 12 | 13 | NuGet←find_nuget_api 14 | :For name :In ⊆name 15 | 'No such test'⎕SIGNAL(3≠⎕NC'test_',name)/6 16 | folder←MkUniqueDir tmpDir,'/',name ⍝ unique folder for this test is created in tmpDir (which is deleted by "teardown_nuget") 17 | NuGet.Setup folder 18 | ⍎'R←test_',name,' folder' 19 | :If 0<≢∊R 20 | r,←(⊂' test_',name,': '),¨⊆R 21 | :EndIf 22 | :EndFor 23 | -------------------------------------------------------------------------------- /APLSource/Tests/test_htmlsanitizer.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_htmlsanitizer project_dir;⎕USING;hs;html;sanitized;expected 2 | r←'' 3 | NuGet.Add project_dir'HtmlSanitizer' 4 | ⎕USING←NuGet.Using project_dir 5 | hs←⎕NEW Ganss.Xss.HtmlSanitizer 6 | 7 | html←'
Test
' 10 | 11 | sanitized←hs.Sanitize html'https://www.example.com'⎕NULL 12 | 13 | expected←'
' 14 | expected,←'Test
' 15 | 16 | :If expected≡sanitized 17 | ⎕←'it works!' 18 | :Else 19 | r←'sanitization failed' 20 | :EndIf 21 | -------------------------------------------------------------------------------- /APLSource/Tests/setup_nuget.aplf: -------------------------------------------------------------------------------- 1 | {r}←setup_nuget nul;bp;path;file;f;d2;z 2 | r←'' 3 | path←({1⊃⎕NPARTS{(-'/\'∊⍨⊢/⍵)↓⍵}⍵}⍣2)##.TESTSOURCE ⍝ go back to grandpa's folder... 4 | ⍝ build the NuGet package and load it - so that we test against the built package (to find functions not included in the API etc.) 5 | bp←⎕SE.Tatin.CreateBuildParms path 6 | file←setup_ResetTempDirs ##.TESTSOURCE 7 | tmpDir←MkUniqueDir(739⌶0),'/NuGet_' ⍝ must be global! (see "test") 8 | (⊂tmpDir)⎕NPUT file 2 ⍝ tempdirs.txt contains all temp dirs created for tests - they'll be deleted in setup_ResetTempDirs 9 | bp.targetPath←tmpDir 10 | ⎕←⎕this 11 | z←{⎕SE.Tatin.(LoadPackages(BuildPackage ⍵)('#'))}bp 12 | ⎕←⎕this 13 | 1 Assert z ⍝ was one package loaded? 14 | f←⎕NL ¯3 15 | f←{((⊂'test_')≡¨5↑¨⍵)/⍵}f 16 | {⎕FX('r←test_',4↓⍵)'r←test 6↓1⊃⎕SI'}¨f 17 | -------------------------------------------------------------------------------- /APLSource/Tests/test_parquet.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_parquet project_dir;path;z;colnames;data;trap;⎕using 2 | r←'' ⍝ no checks here - error will be caught when executed throught DTest or in CITA 3 | trap←0 ⍝ do not catch errors by default 4 | :If 2=⎕NC'##.halt' ⍝ unless ##.halt exists (DTest's flag) 5 | :AndIf ##.halt=0 ⍝ and isn't set to 1 6 | trap←1 7 | :EndIf 8 | :Trap trap/0 ⍝ this test is currently not working, so at least catch the error (unless we run with the "-halt" flag in DTest) 9 | NuGet.Add project_dir'Parquet.Net' 10 | parquet.⎕USING←(NuGet.Using project_dir),⊂'System.IO,System.IO.FileSystem,System.IO.Stream' 11 | 12 | path←(⊃⎕NPARTS 4⊃5179⌶⊃⎕SI),'parquet/' 13 | (data colnames)←parquet.Read path,'userdata1.parquet' 14 | colnames,[0.5]⍪¨10↑¨data 15 | :Else 16 | r←⎕DM 17 | :EndTrap 18 | -------------------------------------------------------------------------------- /APLSource/Tests/parquet/Read.aplf: -------------------------------------------------------------------------------- 1 | Read←{ 2 | ⍝ ⍵ ←→ path to .parquet file 3 | ⍝ ← ←→ (data) (header) 4 | ⍝ ⍵ :: simple char vec 5 | ⍝ data :: inverted table of simple vectors or matrices 6 | ⍝ header :: is a nested vector of character vectors 7 | 8 | ⍝ === NOTE === 9 | ⍝ currently reads a single inverted table from a single row group 10 | ⍝ parquet files may be more complex, design is required 11 | ⍝ for now users can use the following code as a translation template for the low-level API provided 12 | ⍝ https://github.com/aloneguid/parquet-dotnet 13 | 14 | fs←File.OpenRead⊆⍵ 15 | ct←⎕NEW System.Threading.CancellationToken 0 16 | pr←Parquet.ParquetReader.CreateAsync fs ⎕NULL 0 ct 17 | reader←pr.Result 18 | X←((~∊⍨)⊆⊢) ⋄ nl←⎕UCS 10 13 19 | header←⊃¨' 'X¨nl X reader.Schema.ToString 20 | rgr←reader.OpenRowGroupReader 0 21 | data←rgr∘ReadColumns¨reader.Schema.GetDataFields 22 | 23 | data header 24 | } 25 | -------------------------------------------------------------------------------- /APLSource/NuGet/Setup.aplf: -------------------------------------------------------------------------------- 1 | r←Setup project_dir;csproj;xml;project_name;TFM;RID;pkgs;z 2 | :If 0=⎕NC'force' ⋄ force←0 ⋄ :EndIf 3 | project_name←'_',{(1-⌊/(⌽⍵)⍳'\/')↑⍵}project_dir 4 | 5 | (TFM RID)←GetDotNetIDS ⍬ 6 | :If 'net4'≡4↑TFM 7 | ('dotnet ',TFM,' currently not supported')⎕SIGNAL 11 8 | :EndIf 9 | ⍝ Ask dotnet to create a .csproj file 10 | 11 | :If ⎕NEXISTS csproj←project_dir,'/',project_name,'.csproj' 12 | r←'Project file "',csproj,'" already exists ' 13 | :If 0=≢pkgs←Packages project_dir 14 | r,←' (no packages)' 15 | :Else 16 | r,←'with package(s): ',(¯1↓2↓∊', '∘,¨⍕¨pkgs) 17 | :EndIf 18 | →0 19 | :EndIf 20 | 21 | z←↑⎕CMD CmdPaths'dotnet new classlib --target-framework-override ',TFM,' --output ',project_dir,' --name ',project_name 22 | (xml csproj)←CSProjXML project_dir 23 | :If ~(⊂'LangVersion')∊xml[;2] ⍝ Add latest LangVersion 24 | xml⍪←2 'LangVersion' 'Latest'⍬ 5 25 | (⊂⎕XML xml)⎕NPUT csproj 1 26 | :EndIf 27 | 28 | r←'Created project file "',csproj,'"' 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dyalog 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /APLSource/Tests/test_mailkit.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_mailkit project_dir;server;user;pass;ct;client;starttls;i;n;msg;⎕USING 2 | r←'' 3 | server←'mail.dyalog.com' 4 | user←'qa-internal@dyalog.com' 5 | :If 0=≢pass←2 ⎕NQ'.' 'GetEnvironment' 'POP3_QA_INTERNAL' 6 | r←'Environment variable POP3_QA_INTERNAL not set - cannot run test_mailkit' 7 | →0 8 | :EndIf 9 | 10 | NuGet.Add project_dir'MimeKit/3.5.0' 'MailKit/3.5.0' 11 | ⎕USING←'System.Threading' 'MailKit.Net.Pop3',NuGet.Using project_dir 12 | ct←⎕NULL ⍝ Alternatively (⎕NEW CancellationToken 0) 13 | 14 | client←⎕NEW Pop3Client 15 | starttls←MailKit.Security.SecureSocketOptions.StartTls 16 | client.Connect server 110 starttls ct 17 | 18 | :Trap 90 19 | client.Authenticate user pass ct 20 | :Else 21 | r←'Unable to authenticate as ',user,' on server ',server 22 | →0 23 | :EndTrap 24 | 25 | ⎕←'You have ',(⍕n←client.Count),' message(s)' 26 | 27 | :For i :In ⍳n 28 | msg←client.GetMessage(i-1)⎕NULL ⎕NULL ⍝ null CancellationToken and ITransferProgress 29 | '[',(⍕i),']' 30 | 'From ',msg.From 31 | 'To ',msg.To 32 | 'Subject: ',msg.Subject 33 | ⎕←' ' 34 | msg.TextBody 35 | ⎕←' ' 36 | :EndFor 37 | -------------------------------------------------------------------------------- /APLSource/NuGet/GetDotNetIDS.aplf: -------------------------------------------------------------------------------- 1 | (TFM RID)←GetDotNetIDS dummy;⎕USING;major;minor;fd;dnv;arch;os;ok;netstatus 2 | ⍝ Return DotNet 3 | ⍝ TFM: Target Framework Moniker (net4N for Framework, netcoreapp3.N, or netN.0 for 6-8) : https://learn.microsoft.com/en-us/dotnet/standard/frameworks 4 | ⍝ RID: Runtime Identifier (win|mac|linux-x64|x86|arm64) : https://learn.microsoft.com/en-us/dotnet/core/rid-catalog 5 | 6 | :If ~ok←2⊃netstatus←2250⌶⍬ 7 | ('No .NET available. 2250⌶ returned ',⍕netstatus) ⎕SIGNAL ok↓11 8 | :EndIf 9 | ⎕USING←'' 10 | 11 | (major minor)←System.Environment.Version.(Major Minor) 12 | dnv←(⍕major),'.',⍕minor 13 | 'Minimum .NET version is 3.0'⎕SIGNAL(3>major)/11 14 | :Select major 15 | :Case 3 ⍝ "core" 16 | TFM←'netcoreapp',dnv 17 | 18 | :Case 4 ⍝ Framework: see if we can get more detailed information 19 | :If 0≠≢fd←{0::⍵ ⋄ System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}'' 20 | arch←System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture 21 | dnv←∊2↑'.'(≠⊆⊢)⊃⌽' '(≠⊆⊢)fd 22 | :EndIf 23 | TFM←'net',dnv∩⎕D 24 | :Else ⍝ 5+ 25 | TFM←'net',dnv 26 | :EndSelect 27 | 28 | :If major≠4 ⍝ Framework has this in corelib 29 | ⎕USING←',System.Runtime',(major<7)/'.InteropServices.RuntimeInformation' 30 | :EndIf 31 | arch←System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture 32 | 33 | os←APLVersion 1 34 | os,←(⊃('win' 'mac' 'linux' '')['win' 'mac' 'lin'⍳⊂os]) 35 | 'unidentified OS'⎕SIGNAL(0=≢os)/11 36 | 37 | RID←⎕C os,'-',⍕arch 38 | -------------------------------------------------------------------------------- /APLSource/NuGet/Add.aplf: -------------------------------------------------------------------------------- 1 | r←{opt}Add args;project_dir;newpkgs;new;p;newv;old;oldv;pkgs;i;same;bad;add;z;mask;v;cmd 2 | ⍝ ⊃args: project_dir 3 | ⍝ 1↓args: new packages, either 'name' or 'name/version' 4 | ⍝ e.g. Add 'c:\tmp\clocktest\ 'Clock' 5 | ⍝ opt is a boolean flag (Default=1) that controls if we should Publish the project. 6 | 7 | args←,⊆args 8 | project_dir←⊃args 9 | :If 0=⎕NC'opt' 10 | opt←1 11 | :EndIf 12 | ('directory not found: ',project_dir)⎕SIGNAL(⎕NEXISTS project_dir)↓11 13 | ('not a directory: ',project_dir)⎕SIGNAL(1=1 ⎕NINFO project_dir)↓11 14 | project_dir,←('/\'∊⍨⊢/project_dir)↓'/' 15 | 16 | newpkgs←1↓args 17 | new←(¯1+p←newpkgs⍳¨'/')↑¨newpkgs 18 | newv←p↓¨newpkgs 19 | 20 | (old oldv)←↓⍉↑pkgs←Packages project_dir 21 | 22 | i←⍸(new∊old)∧0=≢¨newv ⍝ Actually already registered and version not specified 23 | newv[i]←oldv[old⍳new[i]] ⍝ Update to existing version 24 | 25 | same←⍸new∊old ⍝ Already registered 26 | same←(⍳≢new)∊(newv[same]≡oldv[old⍳new[same]])/i ⍝ With the same version 27 | ⍝ research suggests the following is wrong, just "dotnet add" again to change version 28 | ⍝:If 0≠≢i←i/⍨newv[i]≢oldv[old⍳new[i]] 29 | ⍝ ('already registered with a different version: ',,⍕pkgs[old⍳new[i]])⎕SIGNAL 11 30 | ⍝:EndIf 31 | 32 | bad←0⍨¨new 33 | r←'' 34 | r,←'Already registered: '∘,¨same/new 35 | :For i :In ⍸~same 36 | add←(i⊃new),(0≠≢v)/' --version ',v←i⊃newv 37 | cmd←'dotnet add ',project_dir,' package ',add 38 | z←CMD cmd 39 | mask←∨/¨'error: '∘⍷¨z 40 | :If bad[i]←∨/mask 41 | r,←⊂'Error: ',add 42 | r,←mask/z 43 | :Else 44 | r,←⊂'Added/Updated: ',add 45 | :EndIf 46 | :EndFor 47 | 48 | :If opt∧bad∧.⍱same ⍝ Publish if something was added 49 | z←Publish project_dir ⍝ Returns contents of published folder 50 | :EndIf 51 | r←⍪r 52 | -------------------------------------------------------------------------------- /APLSource/Tests/setup_ResetTempDirs.aplf: -------------------------------------------------------------------------------- 1 | file←setup_ResetTempDirs folder;d2;f;v 2 | ⍝ The challenge is that every test creates a temp dir in order to execute NuGet with an empty project folder. 3 | ⍝ But our very own "teardown" will not be able to delete these folder as they may still be locked by still having links 4 | ⍝ to the dlls. With .NET Framework, there is a way to deal with it ("close appdomain"), but that's not 5 | ⍝ available with .NET Core. So the solution for both cases is to maintain a persistent list of temp dirs 6 | ⍝ and then at the beginning of a test run, we try to delete them. (Likely "leftovers" from previous session.) 7 | v←0 8 | :If 2=⎕NC'##.verbose' 9 | :AndIf ##.verbose 10 | v←1 11 | :EndIf 12 | :If ⎕NEXISTS file←folder,'tempdirs.txt' ⍝ if the file exists 13 | d2←⍬ 14 | :For f :In 1⊃⎕NGET file 1 15 | :If '//'≢2↑f ⍝ ignore line comments 16 | :Select {0::¯2 ⋄ ~⎕NEXISTS ⍵:¯1 ⋄ 2⎕NDELETE ⍵}f 17 | :Case ¯2 ⍝ error deleting folder (permissions or locked files etc.) 18 | d2,←⊂f ⍝ keep it in the list 19 | :If v 20 | ⎕←'Error deleting "',f,'" - will keep in list' 21 | ⎕←(⎕json⍠'Compact'0) ⎕dmx 22 | :EndIf 23 | :Case ¯1 ⍝ does not exist (nothing to do) 24 | :If v 25 | ⎕←'"f" does not exist - removed from list' 26 | :EndIf 27 | :Case 1 ⍝ successful delete (0 ) 28 | :If v 29 | ⎕←'Deleted temp dir:',f 30 | :EndIf 31 | :Case 0 ⍝ hmm, is that even possible? 32 | d2,←⊂f ⍝ keep it in the list anyway to try again later 33 | :EndSelect 34 | :Else 35 | d2,←⊂f ⍝ keep comments in the list 36 | :EndIf 37 | :EndFor 38 | :If 2<≢d2 39 | (⊂d2)⎕NPUT file 1 40 | :Else 41 | ⎕NDELETE file 42 | →createFile 43 | :EndIf 44 | :Else 45 | createFile: 46 | (⊂'// This file contains all temp dirs created for tests - ideally to be deleted in teardown_nuget' '// but because of locked files this may not possible in the same session - so we maintain a persistent list and check it before a new run...')⎕NPUT file 47 | :EndIf 48 | -------------------------------------------------------------------------------- /CITA.json5: -------------------------------------------------------------------------------- 1 | { 2 | "defaults": { // all of these entries can also be provided (and tweaked) per test. 3 | // btw: casing of names is not important 4 | "bits": [32,64], // if you want to bind tests to specific bitness 5 | //"context":"C|o|Q", // can be left out, might be needed in very special cases... 6 | // "env": { 7 | // "foo": "goo" // specific environment vars or config settings 8 | // } 9 | "dyalogversions": "19-", // you may want to change this at the level of individual tests... 10 | "editions":["unicode"], // ..or editions 11 | //*** YOU NEED TO PICK ONE EMAIL ENTRY ONLY! *** 12 | //"email": "me@dyalog.com", // send test result to... (can be as simple as this) 13 | "email": ["committer"], // or a list of addresses 14 | //"email": { // and an object with specific fields 15 | // "Error|OK|All|Change": ["me@dyalog.com"], // for various results ("NB": "change" not yet supported) 16 | // } , 17 | // "net": ["none","default", // you may want to associate certain tests with specific versions of .NET 18 | // "3.1","4.8", 19 | // "6.0","7.0","8.0"], 20 | "platforms": ["win"], 21 | "secondstimeout": 180, // 5 minutes - might be too short for some tests, adjust if needed! 22 | "usehmon":0, // experimental: use health monitor to collect info while test is running 23 | "jenkins_secrets": { // one or more Jenkins Secrets that will be available when the test runs 24 | id: "f01100d7-6953-426a-990c-167cc9f36368", // id 25 | name: "POP3_QA_INTERNAL", // value will be acccessible through this environment variable 26 | } 27 | }, 28 | "tests": [ 29 | { 30 | "id": "nuget", 31 | "test": "./APLSource/Tests/nuget.dyalogtest", 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /APLSource/Tests/test_selenium.aplf: -------------------------------------------------------------------------------- 1 | {r}←test_selenium project_dir;using;prefixes;path;drv;exp;⎕USING;pwf;os 2 | r←'' ⍝ no checks here - error will be caught when executed throught DTest or in CITA 3 | ⍝ we test to stepwise add libraries to the project (avoiding the "Publish" step) 4 | 0 NuGet.Add project_dir'Selenium.WebDriver' 5 | 0 NuGet.Add project_dir'Selenium.WebDriver.ChromeDriver' 6 | ⍝ the next one is a bit tricky because we need to a version of the library that matches the version of the WebDriver that was loaded. 7 | ⍝ we didn't specify one when loading the WebDriver - so Selenium4 fetched the one that matches our browser! 8 | ⍝ Our .csproj will have a line like this: 9 | ⍝ 10 | ⍝ ↑↑↑↑↑↑ and that is the info we need! regex below will extract it.... 11 | 0 NuGet.Add project_dir('Selenium.Support/',⊃('"Selenium.WebDriver" Version="(.*)"'⎕S'\1')1⊃⎕NGET{⎕←⍵,'/_',(2⊃⎕NPARTS ⍵),'.csproj'}project_dir) 12 | 0 NuGet.Add project_dir'WebDriverManager/2.17.6' 13 | NuGet.Publish project_dir 14 | prefixes←'OpenQA' 'OpenQA.Selenium' 'OpenQA.Selenium.Chrome' 'OpenQA.Selenium.Support.UI' 'WebDriverManager' 'WebDriverManager.DriverConfigs.Impl' 'WebDriverManager.Helpers' ⍝ paths into libraries that we need in ⎕USING 15 | ⎕USING←'System' 'System.Drawing,System.Drawing.Primitives' 'System.IO,System.IO.dll',prefixes,NuGet.Using project_dir 16 | path←(NuGet.BinFolder project_dir),'/chromedriver',('win'≡⎕C 3↑1⊃# ⎕WG'APLVersion')/'.exe' 17 | 18 | :Select ⎕C 3↑1⊃'.'⎕WG'APLVersion' 19 | :Case 'win' 20 | os←'windows' 21 | :Case 'mac' 22 | os←'macos' 23 | :Case 'lin' 24 | os←'linux' 25 | :Else 26 | ('Unknow OS: ',⎕C 3↑1⊃'.'⎕WG'APLVersion')⎕SIGNAL 11 27 | :EndSelect 28 | Environment.SetEnvironmentVariable('SE_MANAGER_PATH'({'\'@('/'∘=)⍵}⊃⊃0(⎕NINFO⍠('Recurse' 1)('Wildcard' 1))(project_dir,'/selenium-manager*.*'))) 29 | 30 | ⍝ we're simply creating a new instance - SeleniumManager ensures it's compatible with the locally installed version (requires chrome to be installed, though) 31 | drv←⎕NEW ChromeDriver 32 | drv.Url←'https://dyalog.com' 33 | ⎕DL 5 34 | :If drv.Title≢exp←'Home - Dyalog' 35 | r←'did not get expected page title "',exp,'" but "',drv.Title,'"' 36 | :Else 37 | ⎕←'Successfully loaded ',drv.Title 38 | :EndIf 39 | 40 | pwf←⎕NEW PopupWindowFinder drv ⍝ simple check if the fn from Support.UI is available (will error otherwise) 41 | 42 | drv.Quit 43 | -------------------------------------------------------------------------------- /APLSource/NuGet/Using.aplf: -------------------------------------------------------------------------------- 1 | using_paths←{opts} Using project_dir;deps;d;k;v;t;pkg_name;pkgrt;dll;pkgs;ns;jsname;tgts;z;dlls;children;p;folder;name;opts;opts_mat;all_pkgs;keys;vals;def_opts;includePrimary;includePkgs;excludePkgs 2 | ⍝ Return list of DLL paths for ⎕USING based on a primary DLL and the direct dependencies for a dotnet project published via NuGet 3 | ⍝ args is expected to have one of three forms: 4 | ⍝ 1. a string signifying the project directory; or 5 | ⍝ 2. a list with the project directory as first element and a key-value pairs as other elements; or 6 | ⍝ 3. a list of key-value pairs 7 | ⍝ 8 | ⍝ The key-value part of args is interpreted as a map from options to values. Currently the following options are supported: 9 | ⍝ * project_dir is the project directory; it must be signified if args is a pure list of key-value pairs 10 | ⍝ * include_primary is a boolean signifying whether (1) or not (0) the path to the primary DLL is included in the output. 11 | ⍝ Its standard value is 1. 12 | ⍝ * exclude_pkgs is a list of package names (without version number!) to be excluded in the output 13 | ⍝ Its standard value is ⍬ 14 | ⍝ * include_pkgs is a list of package names (without version number!) to be included in the output 15 | ⍝ Its standard value is ⍬ 16 | ⍝ The parameter exclude_pkgs takes precedence over include_pkgs and giving include_pkgs a value of ⍬ means to include all packages. 17 | 18 | def_opts←⎕NS '' 19 | def_opts.(includePrimary includePkgs excludePkgs)←1 ⍬ ⍬ 20 | :Select ⊃⎕NC 'opts' 21 | :Case 0 22 | opts←⎕NS '' 23 | :Case 2 24 | opts←⎕SE.Dyalog.Array.Deserialise opts 25 | :EndSelect 26 | 'def_opts' ⎕NS opts 27 | (includePrimary includePkgs excludePkgs)←def_opts.(includePrimary includePkgs excludePkgs) 28 | 29 | jsname←7162⌶ ⍝ JSON Translate Name 30 | 31 | pkgs←(~excludePkgs∊⍥⎕C⍨1⊃¨all_pkgs)/all_pkgs←Packages project_dir 32 | :If 0<≢includePkgs 33 | pkgs←(includePkgs∊⍥⎕C⍨1⊃¨pkgs)/pkgs 34 | :EndIf 35 | 36 | 37 | :If 0≠≢deps←findfile project_dir,'/*.deps.json' 38 | :OrIf 0≠≢deps←findfile project_dir,'/published/*.deps.json' 39 | 40 | (d k v t)←↓⍉⎕JSON ⎕OPT'Format' 'M'⊃⎕NGET deps 41 | ⍝ Depth, Key, Value, Type 42 | {}2{p[⍵]←⍺[⍺⍸⍵]}⌿⊢∘⊂⌸d⊣p←⍳≢d ⍝ Parent vector p 43 | ⍝ Descendant of pkgs and key≡"runtime" 44 | pkg_name←⎕C⊃¨'/'(≠⊆⊢)¨k ⍝ e.g. Clock/1.0.3 → Clock 45 | pkgrt←(k∊⊂'runtime')(∧⍤1){⍵∨⍵[p]}⍤1⍣≡pkg_name(∊⍤1 0)⊃¨⎕C pkgs 46 | ⍝ Child of "runtime" key is path to .dll 47 | ⍝ file name key parent is "runtime" 48 | ⍝ dll←⊃∘⌽¨'/'(≠⊆⊢)¨k⌿⍤1⍨(⊂p)⌷⍤1⊢pkgrt 49 | dll←∊¨1↓¨⎕NPARTS(∨⌿pkgrt[;p])/k 50 | using_paths←(project_dir,'/published/')∘,¨dll 51 | 52 | (folder name)←2↑⎕NPARTS ¯10↓deps 53 | 54 | ⍝ Possibly include primary DLL 55 | :If includePrimary 56 | :AndIf ⎕NEXISTS dll←(∊folder name),'.dll' 57 | using_paths,←⊂dll 58 | :EndIf 59 | 60 | :Else ⍝ No deps.json file 61 | 'NuGet support currently requires .NET 6.0 or later' ⎕SIGNAL (2=⊃2250⌶0)/11 62 | 'Unable to locate deps.json file' ⎕SIGNAL 11 ⍝ /// Different strategy required for Framework 63 | using_paths←{(~(2⊃¨⎕NPARTS ⍵)∊⊂project_name)/⍵}(⊃⎕NINFO⍠1⊢project_dir,'/published/*.dll') 64 | :EndIf 65 | using_paths←',',¨using_paths 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NuGet 2 | 3 | A tool to help use NuGet packages from Dyalog APL. 4 | 5 | This code is used by [Cider](https://github.com/aplteam/Cider) to support NuGet packages as project dependencies. It requires Dyalog v19.0 and .NET 6.0 or later. 6 | 7 | The code can also be used outside of Cider, but documentation is currently rudimentary, consisting only in the form of this README file and the example code in the `Tests/` folder. 8 | 9 | ## Introduction 10 | The NuGet tool works by tapping into the "dotnet" command line tool to establish a folder as a .NET project, and use tools built in to .NET to load NuGet packages. It requires .NET 6.0 or later, and Dyalog APL must be configured to use the new .NET by setting DYALOG_NETCORE=1. 11 | 12 | ## Using NuGet with Cider 13 | 14 | Please refer to the Cider documentation for instructions. At the time this was written, the user command to set up a NuGet dependency was `]CIDER.AddNuGetDependencies`. 15 | 16 | ## Brief API documentation 17 | 18 | ### `NuGet.Setup projectdir` 19 | Makes the initial call to the dotnet command to create a .NET project in the named directory. This must be called first. Example: 20 | 21 | ``` 22 | NuGet.Setup '/tmp/nuget-test' 23 | Created project file "/tmp/nuget-test/nuget-test.csproj" 24 | ``` 25 | 26 | ### `{pub}NuGet.Add projectdir packageid` 27 | 28 | Adds a NuGet package as a dependency of the project found in the named directory and (optionally) publishes the package. The package name can optionally be followed by a version number; if no version is provided the latest will be used. Example: 29 | 30 | ``` 31 | NuGet.Add '/tmp/nuget-test' 'Clock/1.0.3' 32 | Added/Updated: Clock 33 | ``` 34 | 35 | The optional left argument `pub`can be used to control whether the package should be 36 | published (1, default) or not (0). When adding several packages, you can save time by not publishing during the individual `Add`s, but by using `pub=0` and calling `Publish` afterwards. 37 | 38 | ### `NuGet.BinFolder projectdir` 39 | 40 | Returns the fully qualified path to the binary output directory for a .NET project. 41 | 42 | The function prioritizes Debug builds if both Debug and Release folders exist. The target framework (e.g., net6.0, net8.0) is automatically appended to create the complete binary path. 43 | 44 | ### `⎕USING←NuGet.Using projectdir` 45 | 46 | Returns the ⎕USING setting that will make it possible to reference the entry points of the added packages. Example: 47 | 48 | ``` 49 | ]box on 50 | Was OFF 51 | NuGet.Using project_dir 52 | ┌────────────────────────────────────┬─────────────────────────────────────────┐ 53 | │,/tmp/nuget-test/published/Clock.dll│,/tmp/nuget-test/published/nuget-test.dll│ 54 | └────────────────────────────────────┴─────────────────────────────────────────┘ 55 | ``` 56 | 57 | If you do not want to include the DLL which represents the empty C# executable that was created by the dotnet command, you can specify this as follows: 58 | 59 | ``` 60 | '(includePrimary: 0)' NuGet.Using project_dir 61 | ┌────────────────────────────────────┐ 62 | │,/tmp/nuget-test/published/Clock.dll│ 63 | └────────────────────────────────────┘ 64 | ``` 65 | 66 | ### `NuGet.Packages projectdir` 67 | 68 | Returns the current list of dependencies:: 69 | 70 | ``` 71 | NuGet.Packages project_dir 72 | ┌─────────────┐ 73 | │┌─────┬─────┐│ 74 | ││Clock│1.0.3││ 75 | │└─────┴─────┘│ 76 | └─────────────┘ 77 | ``` 78 | 79 | ### `NuGet.Publish projectdir` 80 | 81 | Publishes the project and its dependencies to a `/published` folder within the project directory. This step is automatically performed when adding packages (unless disabled with `pub=0` in `Add`), but can be called separately when needed. 82 | 83 | ### `NuGet.Version` 84 | 85 | Returns the current NuGet version number: 86 | 87 | ``` 88 | NuGet.Version 89 | 0.2.0 90 | ``` 91 | 92 | 93 | ## Running the Tests 94 | 95 | To run the tests in Dyalog version 19.0, you must: 96 | 97 | * Make sure you have installed .NET 6.0 or later and set the configuration parameter DYALOG_NETCORE=1 (this is the default under Linux and macOS but not under Windows) 98 | * Either load the Tatin package using `]TATIN.LoadPackages dyalog-nuget`, followed by `]get https://github.com/dyalog/nuget/tree/main/APLSource/Tests`, or 99 | * `]get https://github.com/dyalog/nuget/tree/main/APLSource -unpack`, which will establish both `NuGet` and `Tests` in the workspace. 100 | 101 | To get a list of runnable tests: 102 | 103 | ``` 104 | Tests.test '' 105 | The current test functions exist: 106 | test_clock test_humanizer test_htmlsanitizer test_mailkit test_parquet test_selenium 107 | ``` 108 | 109 | To run a test: 110 | 111 | ``` 112 | Tests.test 'selenium' 113 | Created project file "/tmp/nuget-test/nuget-test.csproj" 114 | Added/Updated: Selenium.WebDriver Selenium.WebDriver.ChromeDriver 115 | Successfully loaded Dyalog - Home 116 | ``` 117 | 118 | Note that you cannot run more than one test per APL session, because once the DLL's are loaded by the interpreter, there is currently no way to unload them. --------------------------------------------------------------------------------