1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-24 19:51:19 +00:00

Compare commits

...

50 Commits

Author SHA1 Message Date
Allan Bowe
c58b5c7a52 Merge pull request #332 from sasjs/patches
fix: invalid macro variable in mp_lockanytable.sas
2023-04-07 11:30:04 +01:00
Allan Bowe
22c7e5b4dd Merge branch 'main' into patches 2023-04-07 11:29:30 +01:00
allan
244171f8c4 fix: failing test due to missing sashelp table, also added scope check 2023-04-06 13:41:02 +01:00
Allan Bowe
fd765e2d68 Merge pull request #333 from sasjs/vpn
github action vpn
2023-04-06 12:07:56 +01:00
840cb5ef44 chore: ci - sas9.4gl.io 2023-04-06 11:16:25 +02:00
918ce96fce chore: ci - jammy ubuntu 2023-04-05 23:07:35 +02:00
f1712c34e8 chore: ci - jammy ubuntu 2023-04-05 22:58:48 +02:00
11ec20b472 chore: ci - jammy ubuntu 2023-04-05 22:54:50 +02:00
f42f111462 chore: ci - jammy ubuntu 2023-04-05 22:49:45 +02:00
907725c5ba chore: ci - jammy ubuntu 2023-04-05 22:48:09 +02:00
95b78b91e1 chore: ci release 2023-04-05 22:46:17 +02:00
e4771b9c14 ci: trigger 2023-04-05 22:24:18 +02:00
ba8190883e chore: ci added vpn for sas9 2023-04-05 22:13:13 +02:00
allan
32dd057e83 fix: avoid open file handle when the variable to find is not provided (in mf_existvar)
Includes a test that was failing and is now passing
2023-04-05 15:29:53 +01:00
allan
7471bd42a4 fix: invalid macro variable in mp_lockanytable.sas 2023-04-05 14:55:00 +01:00
munja
702a4ecd3a chore(lint): adding lineendings rule (LF) 2023-03-31 13:58:30 +01:00
Allan Bowe
5da97295ff Merge pull request #330 from sasjs/issue329
fix: closes #329 by handling the case of unlocking a table that was n…
2023-02-16 14:35:29 +00:00
munja
dc556bdef0 fix: closes #329 by handling the case of unlocking a table that was never locked in mp_lockanytable.sas, also created a corresponding test plus an extra test to check for scope leakage. all.sas was regenerated. 2023-02-16 14:33:53 +00:00
Allan Bowe
111731bf35 Merge pull request #328 from sasjs/all-contributors/add-henrik-forsell
docs: add henrik-forsell as a contributor for doc
2023-02-15 09:32:09 +00:00
allcontributors[bot]
2c526cf9dd docs: update .all-contributorsrc [skip ci] 2023-02-15 09:31:52 +00:00
allcontributors[bot]
660e02193f docs: update README.md [skip ci] 2023-02-15 09:31:51 +00:00
Allan Bowe
00b4dee86e Merge pull request #327 from henrik-forsell/doc-fix
Changed documentation wording (Column to Dataset)
2023-02-15 09:28:50 +00:00
Henrik Forsell
3913825c22 Changed documentation wording (Column to Dataset) 2023-02-15 15:57:11 +13:00
Allan Bowe
0f143d603b Merge pull request #326 from sasjs/325-error-the-keyword-parameter-maxobs-was-not-defined-with-the-macro
fix: closes #325 by including maxobs param
2023-02-13 14:05:36 +00:00
munja
f1d5fa2c0a fix: closes #325 by including maxobs param 2023-02-13 14:01:43 +00:00
Allan Bowe
a88689428f fix: updating cycjimmy/semantic-release-action to v3 2023-01-25 12:56:38 +00:00
munja
8843fa8bfc fix: adding nrstr() wrapper in mm_adduser2group 2023-01-25 12:53:10 +00:00
Allan Bowe
22d046cf5c Merge pull request #324 from sasjs/servertestfixes
fix: updating ms_runstp and ms_testservice macros to cater for latest…
2023-01-06 13:15:11 +01:00
munja
29e3eb34aa fix: updating ms_runstp and ms_testservice macros to cater for latest response JSON formats in sasjs/server 2023-01-06 12:13:36 +00:00
munja
1af52a6683 fix: adding des= macro option to mf_abort 2023-01-02 11:26:21 +00:00
munja
fc0c96dd94 chore: merge 2022-12-30 12:41:08 +00:00
munja
b9c4882553 fix: linting issues 2022-12-30 12:38:34 +00:00
Allan Bowe
011b2b185c chore: removing broken badges in README 2022-12-28 20:25:05 +00:00
Allan Bowe
dbc23550ac Merge pull request #323 from sasjs/ms_getgroups
fix: increasing desc length to 256 in ms_getgroups
2022-12-28 21:21:35 +01:00
munja
8910840ccc fix: increasing desc length to 256 in ms_getgroups 2022-12-28 20:17:08 +00:00
Allan Bowe
4ef571032d Merge pull request #322 from sasjs/upds
Upds
2022-12-14 14:21:20 +01:00
Allan Bowe
e01cd8cd16 Merge branch 'main' into upds 2022-12-14 14:20:51 +01:00
munja
00628ec78a chore: updating lint settings, some line ending issues, and a sasjsconfig apploc fix 2022-12-14 14:19:28 +01:00
munja
f4e6a487f3 fix: removing redundant param in mS/M_webout macros 2022-12-14 14:17:06 +01:00
Allan Bowe
b7afecdf81 fix: escaping syswarningtext and syserrortext in mp_abort 2022-12-04 21:14:10 +00:00
Allan Bowe
19eb348f0e fix: else case for issue #320 2022-12-04 18:59:31 +00:00
Allan Bowe
f420ac2abf Merge pull request #321 from sasjs/issue320
fix: full escaping of syswarningtext and syserrortext. Closes #320
2022-12-04 18:22:52 +00:00
Allan Bowe
7edec1ad8a fix: full escaping of syswarningtext and syserrortext. Closes #320 2022-12-04 18:18:15 +00:00
Allan Bowe
62d7bce249 feat: adding nobs limit to mp_gitlog 2022-12-04 17:23:53 +00:00
munja
fe6c9a793b chore: fixing saspac build 2022-11-30 22:21:58 +01:00
Allan Bowe
8e13943356 Merge pull request #319 from sasjs/gitbranch
3 new macros (and tests) for the core library
2022-11-30 20:43:54 +00:00
munja
04df9600e0 chore: updating all.sas 2022-11-30 21:43:28 +01:00
munja
e2b0aabfa4 feat: mp_gitlog and associated test/docs 2022-11-30 21:35:49 +01:00
munja
c52a623630 feat: new mf_getgitbranch macro (and test) 2022-11-30 20:15:10 +01:00
munja
cf348e8016 feat: new mf_readfile macro (and test) 2022-11-30 20:06:11 +01:00
45 changed files with 2142 additions and 618 deletions

View File

@@ -135,6 +135,15 @@
"contributions": [
"code"
]
},
{
"login": "henrik-forsell",
"name": "Henrik Forsell",
"avatar_url": "https://avatars.githubusercontent.com/u/109935936?v=4",
"profile": "https://github.com/henrik-forsell",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,

25
.github/vpn/config.ovpn vendored Normal file
View File

@@ -0,0 +1,25 @@
# Client
client
tls-client
dev tun
# this will connect with whatever proto DNS tells us (https://community.openvpn.net/openvpn/ticket/934)
proto tcp
remote vpn.4gl.io 7494
resolv-retry infinite
cipher AES-256-CBC
auth SHA256
script-security 2
keepalive 10 120
remote-cert-tls server
# Keys
ca ca.crt
cert user.crt
key user.key
tls-auth tls.key 1
# Security
nobind
persist-key
persist-tun
verb 3

View File

@@ -15,7 +15,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v2
uses: cycjimmy/semantic-release-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -23,6 +23,6 @@ jobs:
run: |
npx @sasjs/cli compile job -s sasjs/utils/create_sas_package.sas -o sasjsbuild
# this part depends on https://github.com/sasjs/server/issues/307
# sasjs run sasjsbuild/makepak.sas -t sas9
# sasjs run sasjsbuild/jobs/utils/create_sas_package.sas -t sas9

View File

@@ -21,6 +21,29 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Write VPN Files
run: |
echo "$CA_CRT" > .github/vpn/ca.crt
echo "$USER_CRT" > .github/vpn/user.crt
echo "$USER_KEY" > .github/vpn/user.key
echo "$TLS_KEY" > .github/vpn/tls.key
shell: bash
env:
CA_CRT: ${{ secrets.CA_CRT}}
USER_CRT: ${{ secrets.USER_CRT }}
USER_KEY: ${{ secrets.USER_KEY }}
TLS_KEY: ${{ secrets.TLS_KEY }}
- name: Install Open VPN
run: |
sudo apt install apt-transport-https
sudo wget https://swupdate.openvpn.net/repos/openvpn-repo-pkg-key.pub
sudo apt-key add openvpn-repo-pkg-key.pub
sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-jammy.list
sudo apt update
sudo apt install openvpn3=17~betaUb22042+jammy
- name: Start Open VPN 3
run: openvpn3 session-start --config .github/vpn/config.ovpn
- name: Install Doxygen
run: sudo apt-get install doxygen
@@ -31,16 +54,10 @@ jobs:
run: npm run lint
- name: Add client
run: echo "CLIENT=${{secrets.CLIENT}}"> .env.viya
- name: Add secret
run: echo "SECRET=${{secrets.SECRET}}" >> .env.viya
run: echo "CLIENT=${{secrets.SAS9_4GL_IO_CLIENT}}"> .env.server
- name: Add access token
run: echo "ACCESS_TOKEN=${{secrets.ACCESS_TOKEN}}" >> .env.viya
- name: Add refresh token
run: echo "REFRESH_TOKEN=${{secrets.REFRESH_TOKEN}}" >> .env.viya
run: echo "ACCESS_TOKEN=${{secrets.SAS9_4GL_IO_ACCESS_TOKEN}}" >> .env.server
- name: Build Project
run: npm run build
@@ -54,4 +71,4 @@ jobs:
SAS_USERNAME: ${{secrets.SAS_USERNAME}}
SAS_PASSWORD: ${{secrets.SAS_PASSWORD}}
ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}}
REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}}
REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}}

4
.gitignore vendored
View File

@@ -10,4 +10,6 @@ sasjsresults/
mc_*
# ignore .env files as they can contain sasjs access tokens
*.env*
*.env*
~

View File

@@ -1,13 +1,15 @@
{
"noTrailingSpaces": true,
"noEncodedPasswords": true,
"hasDoxygenHeader": true,
"hasMacroNameInMend": true,
"hasMacroParentheses": true,
"noNestedMacros": false,
"noSpacesInFileNames": true,
"maxLineLength": 300,
"lowerCaseFileNames": true,
"noTabIndentation": true,
"indentationMultiple": 2
}
"noTrailingSpaces": true,
"noEncodedPasswords": true,
"hasDoxygenHeader": true,
"hasMacroNameInMend": true,
"hasMacroParentheses": true,
"lineEndings": "lf",
"noGremlins": true,
"noNestedMacros": false,
"noSpacesInFileNames": true,
"maxLineLength": 300,
"lowerCaseFileNames": true,
"noTabs": true,
"indentationMultiple": 2
}

View File

@@ -6,5 +6,7 @@
"editor.rulers": [
80
],
"files.trimTrailingWhitespace": true
"files.trimTrailingWhitespace": true,
"sasjs-for-vscode.target": "docsonly",
"sasjs-for-vscode.isLocal": true
}

View File

@@ -2,8 +2,6 @@
[![npm package][npm-image]][npm-url]
[![Github Workflow][githubworkflow-image]][githubworkflow-url]
![npm](https://img.shields.io/npm/dt/@sasjs/core)
![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@sasjs/core)
[![License](https://img.shields.io/apm/l/atomic-design-ui.svg)](/LICENSE)
![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core)
[![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues-raw/sasjs/core)](https://github.com/sasjs/core/issues)
@@ -248,7 +246,7 @@ The following repositories are also worth checking out:
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -256,22 +254,25 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑‍🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
<td align="center"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
<td align="center"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
<td align="center"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
<td align="center"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
</tr>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt="Allan Bowe"/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑‍🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt="rafgag"/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt="Trevor Moody"/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt="Krishna Acondy"/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt="Muhammad Saad "/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt="Yury Shkoda"/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt="Mihajlo Medjedovic"/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt="kkchandok"/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt="Vladislav Parhomchik"/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt="Vignesh T."/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt="Bart Jablonski"/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/henrik-forsell"><img src="https://avatars.githubusercontent.com/u/109935936?v=4?s=100" width="100px;" alt="Henrik Forsell"/><br /><sub><b>Henrik Forsell</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=henrik-forsell" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->

609
all.sas
View File

@@ -30,7 +30,7 @@ options noquotelenmax;
**/
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
)/des='ungraceful abort' /*STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -42,7 +42,8 @@ options noquotelenmax;
%mend mf_abort;
/** @endcond *//**
/** @endcond */
/**
@file
@brief de-duplicates a macro string
@details Removes all duplicates from a string of words. A delimeter can be
@@ -247,7 +248,8 @@ options noquotelenmax;
0
%end;
%mend mf_existfileref;/**
%mend mf_existfileref;
/**
@file
@brief Checks if a function exists
@details Returns 1 if the function exists, else 0. Note that this function
@@ -310,13 +312,17 @@ https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md#functionex
%local dsid rc;
%let dsid=%sysfunc(open(&libds,is));
%if &dsid=0 or %length(&var)=0 %then %do;
%if &dsid=0 %then %do;
%put %sysfunc(sysmsg());
0
0
%end;
%else %if %length(&var)=0 %then %do;
0
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%end;
%mend mf_existvar;
@@ -781,6 +787,43 @@ or %index(&pgm,/tests/testteardown)
/* send them out without spaces or quote markers */
%do;%unquote(%upcase(&fmt))%end;
%mend mf_getfmtname;/**
@file
@brief Retrieves the current branch from a local GIT repo
@details In a local git repository, the current branch is always available in
the `.git/HEAD` file in a format like this: `ref: refs/heads/master`
This macro simply reads the file and returns the last word (eg `master`).
Example usage:
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&gitdir));
%put The current branch is %mf_getgitbranch(&gitdir);
@param [in] gitdir The directory containing the GIT repository
<h4> SAS Macros </h4>
@li mf_readfile.sas
<h4> Related Macros </h4>
@li mp_gitadd.sas
@li mp_gitlog.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
@version 9.2
@author Allan Bowe
**/
%macro mf_getgitbranch(gitdir
)/*/STORE SOURCE*/;
%scan(%mf_readfile(&gitdir/.git/HEAD),-1)
%mend mf_getgitbranch;
/**
@file
@brief retrieves a key value pair from a control dataset
@details By default, control dataset is work.mp_setkeyvalue. Usage:
@@ -1902,6 +1945,69 @@ Usage:
)/*/STORE SOURCE*/;
%mf_getattrn(&libds,NLOBS)
%mend mf_nobs;/**
@file
@brief Reads the first line of a file using pure macro
@details Reads the first line of a file and returns it. Future versions may
read each line into a macro variable array.
Generally, reading data into macro variables is not great as certain
nonprintable characters (such as CR, LF) may be dropped in the conversion.
Usage:
%mf_writefile(&sasjswork/myfile.txt,l1=some content,l2=more content)
%put %mf_readfile(&sasjswork/myfile.txt);
@param [in] fpath Full path to file to be read
<h4> Related Macros </h4>
@li mf_deletefile.sas
@li mf_writefile.sas
@li mf_readfile.test.sas
@version 9.2
@author Allan Bowe
**/
/** @cond */
%macro mf_readfile(fpath
)/*/STORE SOURCE*/;
%local fref rc fid fcontent;
/* check file exists */
%if %sysfunc(filename(fref,&fpath)) ne 0 %then %do;
%put &=fref &=fpath;
%put %str(ERR)OR: %sysfunc(sysmsg());
%return;
%end;
%let fid=%sysfunc(fopen(&fref,I));
%if &fid=0 %then %do;
%put %str(ERR)OR: %sysfunc(sysmsg());
%return;
%end;
%if %sysfunc(fread(&fid)) = 0 %then %do;
%let rc=%sysfunc(fget(&fid,fcontent,65534));
&fcontent
%end;
/*
%do %while(%sysfunc(fread(&fid)) = 0);
%let rc=%sysfunc(fget(&fid,fcontent,65534));
&fcontent
%end;
*/
%let rc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(&fref));
%mend mf_readfile;
/** @endcond */
/**
@file mf_trimstr.sas
@brief Removes character(s) from the end, if they exist
@details If the designated characters exist at the end of the string, they
@@ -2442,15 +2548,51 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ",""SYSERRORTEXT"" : " syserrortext;
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ",""SYSWARNINGTEXT"" : " syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
put "}" ;
@@ -2776,7 +2918,7 @@ run;
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
@version 9.2
@author Allan Bowe
@@ -2850,7 +2992,7 @@ run;
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
<h4> Related Macros </h4>
@@ -8212,6 +8354,110 @@ data _null_;
run;
%mend mp_gitadd;
/**
@file
@brief Creates a dataset with the commit history of a local repository
@details Returns the commit history from a local repository. The name of the
branch is also returned.
More details here:
https://documentation.sas.com/doc/ko/pgmsascdc/v_033/lefunctionsref/n1qo5miyvry1nen111js203hlwrh.htm
Usage:
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&dir));
%mp_gitlog(&gitdir,outds=work.mp_gitlog)
@param [in] gitdir The directory containing the GIT repository
@param [in] filter= (BRANCHONLY) To return only the commits for the current
branch, use BRANCHONLY (the default). Anything else will return the entire
commit history.
@param [out] outds= (work.mp_gitlog) The output dataset to create.
All vars are $128 except `message` which is $4000.
@li author returns the author who submitted the commit.
@li children_ids returns a list of the children commit IDs
@li committer returns the name of the committer.
@li committer_email returns the email of the committer.
@li email returns the email of the commit author.
@li id returns the commit ID of the commit object.
@li in_current_branch returns "TRUE" or "FALSE" to indicate if the commit is
in the current branch.
@li message returns the commit message.
@li parent_ids returns a list of the parent commit IDs.
@li stash returns "TRUE" or "FALSE" to indicate if the commit is a stash
commit.
@li time returns the time of the commit as numeric string
@li commit_time_num time of the commit as numeric SAS datetime
@li commit_time_str the commit_time_num variable cast as string
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [in] nobs= (0) Set to an integer greater than 0 to restrict the number
of rows returned
<h4> SAS Macros </h4>
@li mf_getgitbranch.sas
<h4> Related Files </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
%macro mp_gitlog(gitdir,outds=work.mp_gitlog,mdebug=0,filter=BRANCHONLY,nobs=0);
%local varlist i var;
%let varlist=author children_ids committer committer_email email id
in_current_branch parent_ids stash time ;
data &outds;
LENGTH gitdir branch $ 1024 message $4000 &varlist $128 commit_time_num 8.
commit_time_str $32;
call missing (of _all_);
branch="%mf_getgitbranch(&gitdir)";
gitdir=symget('gitdir');
rc=git_status_free(trim(gitdir));
if rc=-1 then do;
put "The libgit2 library is unavailable and no Git operations can be used.";
put "See: https://stackoverflow.com/questions/74082874";
stop;
end;
else if rc=-2 then do;
put "The libgit2 library is available, but the status function failed.";
put "See the log for details.";
stop;
end;
entries=git_commit_log(trim(gitdir));
do n=1 to entries;
%do i=1 %to %sysfunc(countw(&varlist message));
%let var=%scan(&varlist message,&i,%str( ));
rc=git_commit_get(n,trim(gitdir),"&var",&var);
%end;
/* convert unix time to SAS time - https://4gl.uk/corelink0 */
/* Number of seconds between 01JAN1960 and 01JAN1970: 315619200 */
format commit_time_num datetime19.;
commit_time_num=sum(input(cats(time),best.),315619200);
commit_time_str=put(commit_time_num,datetime19.);
%if &mdebug=1 %then %do;
putlog (_all_)(=);
%end;
if "&filter"="BRANCHONLY" then do;
if cats(in_current_branch)='TRUE' then output;
end;
else output;
%if &nobs>0 %then %do;
if n ge &nobs then stop;
%end;
end;
rc=git_commit_free(trim(gitdir));
keep gitdir branch &varlist message time commit_time_num commit_time_str;
run;
%mend mp_gitlog;
/**
@file
@brief Pulls latest release info from a GIT repository
@@ -8348,7 +8594,7 @@ data &outds;
putlog (_all_)(=);
%end;
end;
rc=git_status_free(gitdir);
rc=git_status_free(trim(gitdir));
drop rc cnt;
run;
@@ -10209,7 +10455,7 @@ run;
data _null_;
putlog 'NOTE-' / 'NOTE-';
putlog "NOTE- &sysmacroname: table locked, waiting "@;
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
putlog "NOTE- (iteration &x of &loops)";
putlog 'NOTE-' / 'NOTE-';
run;
@@ -10242,7 +10488,10 @@ run;
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
quit;
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
%if &status=LOCKED %then %do;
%if &sqlobs=0 %then %do;
%put %str(WAR)NING: &lib..&ds has never been locked!;
%end;
%else %if &status=LOCKED %then %do;
data _null_;
putlog "&sysmacroname: unlocking &lib..&ds:";
run;
@@ -13819,7 +14068,8 @@ run;
filename __us2grp temp;
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
<Person Id='%nrstr(&uuri)'>
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
</IdentityGroups></Person></Metadata>
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
out=__us2grp verbose;
@@ -13836,7 +14086,8 @@ run;
filename __us2grp clear;
%mend mm_adduser2group;/**
%mend mm_adduser2group;
/**
@file
@brief Assigns library directly using details from metadata
@details Queries metadata to get the libname definition then allocates the
@@ -16199,7 +16450,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
@@ -16224,7 +16475,25 @@ data _null_;
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
@@ -16237,7 +16506,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';
@@ -16263,9 +16550,11 @@ data _null_;
put ' ';
put '%mend mm_webout; ';
/* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
put ' ,maxobs=MAX';
put ');';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
put ' ,showmeta=&showmeta';
put ' ,showmeta=&showmeta,maxobs=&maxobs';
put ' )';
put '%mend;';
run;
@@ -19845,7 +20134,7 @@ run;
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file _sjsref mod encoding='utf-8';
@@ -19870,7 +20159,25 @@ run;
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
@@ -19883,7 +20190,25 @@ run;
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;
@@ -21213,7 +21538,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
@@ -21234,7 +21559,25 @@ data _null_;
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); ';
put ' put '',"SYSHOSTINFOLONG" : '' SYSHOSTINFOLONG; ';
@@ -21250,7 +21593,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';
@@ -21444,7 +21805,7 @@ filename &headref clear;
@param [in] uid= (0) Provide the userid on which to filter
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
list of groups. Format:
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|NAME:$32.|DESCRIPTION:$256.|GROUPID:best.|
|---|---|---|
|`SomeGroup `|`A group `|`1`|
|`Another Group`|`this is a different group`|`2`|
@@ -21480,7 +21841,7 @@ filename &headref clear;
%if %sysget(MODE)=desktop %then %do;
/* groups api does not exist in desktop mode */
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
name="&sysuserid";
description="&sysuserid (group - desktop mode)";
groupid=1;
@@ -21536,7 +21897,7 @@ libname &libref JSON fileref=&fref1;
%if "&user"="0" and "&uid"="0" %then %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..root;
drop ordinal_root;
@@ -21544,7 +21905,7 @@ libname &libref JSON fileref=&fref1;
%end;
%else %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..groups;
drop ordinal_:;
@@ -21756,8 +22117,9 @@ options &optval;
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_chop.sas
**/
@@ -21870,7 +22232,10 @@ run;
run;
%end;
filename &outref temp lrecl=32767;
%local resp_path;
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
filename &outref "&resp_path" lrecl=32767;
/* prepare request*/
proc http method='POST' headerin=&authref in=&mainref out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
@@ -21878,6 +22243,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
debug level=2;
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
@@ -21893,11 +22259,22 @@ or &mdebug=1
options &optval;
%if &outlogds ne _null_ or &mdebug=1 %then %do;
%local dumplib;
%let dumplib=%mf_getuniquelibref();
libname &dumplib json fileref=&outref;
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("&resp_path"
,matchvar=matchstr
,keep=LAST
,matchpoint=END
,outfile="&chopout"
,mdebug=&mdebug
)
data &outlogds;
set &dumplib..log;
infile "&chopout" lrecl=2000;
length line $2000;
line=_infile_;
%if &mdebug=1 %then %do;
putlog line=;
%end;
@@ -22024,50 +22401,38 @@ run;
)
/* SASjs services have the _webout embedded in wrapper JSON */
/* Files can also be very large - so use a dedicated macro to chop it out */
%local matchstr1 matchstr2 ;
%let matchstr1={"status":"success","_webout":{;
%let matchstr2=},"log":[{;
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
/* chop out JSON section */
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("%sysfunc(pathname(&fref1,F))"
,matchvar=matchstr1
,keep=LAST
,matchpoint=END
,offset=-1
,outfile="&chopout1"
,mdebug=&mdebug
)
%mp_chop("&chopout1"
,matchvar=matchstr2
,matchvar=matchstr
,keep=FIRST
,matchpoint=START
,offset=1
,outfile="&chopout2"
,offset=-1
,outfile="&chopout"
,mdebug=&mdebug
)
%if &outlib ne 0 %then %do;
libname &outlib json "&chopout2";
libname &outlib json "&chopout";
%end;
%if &outref ne 0 %then %do;
filename &outref "&chopout2";
filename &outref "&chopout";
%end;
%if &mdebug=0 %then %do;
filename &webref clear;
filename &fref1 clear;
filename &fref2 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend ms_testservice;/**
%mend ms_testservice;
/**
@file
@brief Send data to/from sasjs/server
@details This macro should be added to the start of each web service,
@@ -22210,7 +22575,7 @@ run;
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file &fref mod encoding='utf-8' termstr=lf;
@@ -22231,7 +22596,25 @@ run;
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
@@ -22247,7 +22630,25 @@ run;
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;
@@ -23825,7 +24226,25 @@ data _null_;
put ' put '',"SYS_JES_JOB_URI" : '' SYS_JES_JOB_URI ; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
@@ -23838,7 +24257,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';
@@ -27632,7 +28069,25 @@ filename &fref1 clear;
put ',"SYS_JES_JOB_URI" : ' SYS_JES_JOB_URI ;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
@@ -27645,7 +28100,25 @@ filename &fref1 clear;
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;

View File

@@ -12,7 +12,7 @@
**/
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
)/des='ungraceful abort' /*STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -24,4 +24,4 @@
%mend mf_abort;
/** @endcond */
/** @endcond */

View File

@@ -30,4 +30,4 @@
0
%end;
%mend mf_existfileref;
%mend mf_existfileref;

View File

@@ -25,13 +25,17 @@
%local dsid rc;
%let dsid=%sysfunc(open(&libds,is));
%if &dsid=0 or %length(&var)=0 %then %do;
%if &dsid=0 %then %do;
%put %sysfunc(sysmsg());
0
0
%end;
%else %if %length(&var)=0 %then %do;
0
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%end;
%mend mf_existvar;

37
base/mf_getgitbranch.sas Normal file
View File

@@ -0,0 +1,37 @@
/**
@file
@brief Retrieves the current branch from a local GIT repo
@details In a local git repository, the current branch is always available in
the `.git/HEAD` file in a format like this: `ref: refs/heads/master`
This macro simply reads the file and returns the last word (eg `master`).
Example usage:
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&gitdir));
%put The current branch is %mf_getgitbranch(&gitdir);
@param [in] gitdir The directory containing the GIT repository
<h4> SAS Macros </h4>
@li mf_readfile.sas
<h4> Related Macros </h4>
@li mp_gitadd.sas
@li mp_gitlog.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
@version 9.2
@author Allan Bowe
**/
%macro mf_getgitbranch(gitdir
)/*/STORE SOURCE*/;
%scan(%mf_readfile(&gitdir/.git/HEAD),-1)
%mend mf_getgitbranch;

63
base/mf_readfile.sas Normal file
View File

@@ -0,0 +1,63 @@
/**
@file
@brief Reads the first line of a file using pure macro
@details Reads the first line of a file and returns it. Future versions may
read each line into a macro variable array.
Generally, reading data into macro variables is not great as certain
nonprintable characters (such as CR, LF) may be dropped in the conversion.
Usage:
%mf_writefile(&sasjswork/myfile.txt,l1=some content,l2=more content)
%put %mf_readfile(&sasjswork/myfile.txt);
@param [in] fpath Full path to file to be read
<h4> Related Macros </h4>
@li mf_deletefile.sas
@li mf_writefile.sas
@li mf_readfile.test.sas
@version 9.2
@author Allan Bowe
**/
/** @cond */
%macro mf_readfile(fpath
)/*/STORE SOURCE*/;
%local fref rc fid fcontent;
/* check file exists */
%if %sysfunc(filename(fref,&fpath)) ne 0 %then %do;
%put &=fref &=fpath;
%put %str(ERR)OR: %sysfunc(sysmsg());
%return;
%end;
%let fid=%sysfunc(fopen(&fref,I));
%if &fid=0 %then %do;
%put %str(ERR)OR: %sysfunc(sysmsg());
%return;
%end;
%if %sysfunc(fread(&fid)) = 0 %then %do;
%let rc=%sysfunc(fget(&fid,fcontent,65534));
&fcontent
%end;
/*
%do %while(%sysfunc(fread(&fid)) = 0);
%let rc=%sysfunc(fget(&fid,fcontent,65534));
&fcontent
%end;
*/
%let rc=%sysfunc(fclose(&fid));
%let rc=%sysfunc(filename(&fref));
%mend mf_readfile;
/** @endcond */

View File

@@ -225,15 +225,51 @@ and %superq(SYSPROCESSNAME) ne %str(Compute Server)
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
put ",""SYSERRORTEXT"" : " syserrortext;
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSSCPL"" : ""&sysscpl"" ";
put ",""SYSSITE"" : ""&syssite"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ",""SYSWARNINGTEXT"" : " syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
put "}" ;

View File

@@ -22,7 +22,7 @@
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
@version 9.2
@author Allan Bowe

View File

@@ -41,7 +41,7 @@
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
<h4> Related Macros </h4>

104
base/mp_gitlog.sas Normal file
View File

@@ -0,0 +1,104 @@
/**
@file
@brief Creates a dataset with the commit history of a local repository
@details Returns the commit history from a local repository. The name of the
branch is also returned.
More details here:
https://documentation.sas.com/doc/ko/pgmsascdc/v_033/lefunctionsref/n1qo5miyvry1nen111js203hlwrh.htm
Usage:
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&dir));
%mp_gitlog(&gitdir,outds=work.mp_gitlog)
@param [in] gitdir The directory containing the GIT repository
@param [in] filter= (BRANCHONLY) To return only the commits for the current
branch, use BRANCHONLY (the default). Anything else will return the entire
commit history.
@param [out] outds= (work.mp_gitlog) The output dataset to create.
All vars are $128 except `message` which is $4000.
@li author returns the author who submitted the commit.
@li children_ids returns a list of the children commit IDs
@li committer returns the name of the committer.
@li committer_email returns the email of the committer.
@li email returns the email of the commit author.
@li id returns the commit ID of the commit object.
@li in_current_branch returns "TRUE" or "FALSE" to indicate if the commit is
in the current branch.
@li message returns the commit message.
@li parent_ids returns a list of the parent commit IDs.
@li stash returns "TRUE" or "FALSE" to indicate if the commit is a stash
commit.
@li time returns the time of the commit as numeric string
@li commit_time_num time of the commit as numeric SAS datetime
@li commit_time_str the commit_time_num variable cast as string
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [in] nobs= (0) Set to an integer greater than 0 to restrict the number
of rows returned
<h4> SAS Macros </h4>
@li mf_getgitbranch.sas
<h4> Related Files </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
%macro mp_gitlog(gitdir,outds=work.mp_gitlog,mdebug=0,filter=BRANCHONLY,nobs=0);
%local varlist i var;
%let varlist=author children_ids committer committer_email email id
in_current_branch parent_ids stash time ;
data &outds;
LENGTH gitdir branch $ 1024 message $4000 &varlist $128 commit_time_num 8.
commit_time_str $32;
call missing (of _all_);
branch="%mf_getgitbranch(&gitdir)";
gitdir=symget('gitdir');
rc=git_status_free(trim(gitdir));
if rc=-1 then do;
put "The libgit2 library is unavailable and no Git operations can be used.";
put "See: https://stackoverflow.com/questions/74082874";
stop;
end;
else if rc=-2 then do;
put "The libgit2 library is available, but the status function failed.";
put "See the log for details.";
stop;
end;
entries=git_commit_log(trim(gitdir));
do n=1 to entries;
%do i=1 %to %sysfunc(countw(&varlist message));
%let var=%scan(&varlist message,&i,%str( ));
rc=git_commit_get(n,trim(gitdir),"&var",&var);
%end;
/* convert unix time to SAS time - https://4gl.uk/corelink0 */
/* Number of seconds between 01JAN1960 and 01JAN1970: 315619200 */
format commit_time_num datetime19.;
commit_time_num=sum(input(cats(time),best.),315619200);
commit_time_str=put(commit_time_num,datetime19.);
%if &mdebug=1 %then %do;
putlog (_all_)(=);
%end;
if "&filter"="BRANCHONLY" then do;
if cats(in_current_branch)='TRUE' then output;
end;
else output;
%if &nobs>0 %then %do;
if n ge &nobs then stop;
%end;
end;
rc=git_commit_free(trim(gitdir));
keep gitdir branch &varlist message time commit_time_num commit_time_str;
run;
%mend mp_gitlog;

View File

@@ -60,7 +60,7 @@ data &outds;
putlog (_all_)(=);
%end;
end;
rc=git_status_free(gitdir);
rc=git_status_free(trim(gitdir));
drop rc cnt;
run;

View File

@@ -167,7 +167,7 @@ run;
data _null_;
putlog 'NOTE-' / 'NOTE-';
putlog "NOTE- &sysmacroname: table locked, waiting "@;
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
putlog "NOTE- (iteration &x of &loops)";
putlog 'NOTE-' / 'NOTE-';
run;
@@ -200,7 +200,10 @@ run;
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
quit;
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
%if &status=LOCKED %then %do;
%if &sqlobs=0 %then %do;
%put %str(WAR)NING: &lib..&ds has never been locked!;
%end;
%else %if &status=LOCKED %then %do;
data _null_;
putlog "&sysmacroname: unlocking &lib..&ds:";
run;

View File

@@ -81,7 +81,8 @@ run;
filename __us2grp temp;
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
<Person Id='%nrstr(&uuri)'>
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
</IdentityGroups></Person></Metadata>
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
out=__us2grp verbose;
@@ -98,4 +99,4 @@ run;
filename __us2grp clear;
%mend mm_adduser2group;
%mend mm_adduser2group;

View File

@@ -546,7 +546,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
@@ -571,7 +571,25 @@ data _null_;
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
@@ -584,7 +602,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';
@@ -610,9 +646,11 @@ data _null_;
put ' ';
put '%mend mm_webout; ';
/* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
put ' ,maxobs=MAX';
put ');';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
put ' ,showmeta=&showmeta';
put ' ,showmeta=&showmeta,maxobs=&maxobs';
put ' )';
put '%mend;';
run;

View File

@@ -150,7 +150,7 @@
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file _sjsref mod encoding='utf-8';
@@ -175,7 +175,25 @@
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
@@ -188,7 +206,25 @@
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;

668
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,6 @@
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
},
"devDependencies": {
"@sasjs/cli": "3.13.0"
"@sasjs/cli": "3.24.0"
}
}

View File

@@ -85,7 +85,7 @@
{
"name": "docsonly",
"serverType": "SASJS",
"appLoc": "dummy",
"appLoc": "/dummy",
"macroFolders": [
"meta",
"metax",

View File

@@ -1,224 +1,224 @@
/**
@file
@brief Deploy repo as a SAS PACKAGES module
@details After every release, this program is executed to update the SASPAC
repo with the latest macros (and same version number).
The program is first compiled using sasjs compile, then executed using
sasjs run.
Requires the server to have SSH keys.
<h4> SAS Macros </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
/* get package version */
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
data _null_;
set splib.root;
call symputx('version',substr(TAG_NAME,2));
run;
/* clone the source repo */
%let dir = %sysfunc(pathname(work))/core;
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
/*
clone the target repo.
If you have issues, see: https://stackoverflow.com/questions/74082874
*/
options dlcreatedir;
libname _ "&dirOut.";
%let dirOut = %sysfunc(pathname(work))/package;
%put tgt clone rc=%sysfunc(GITFN_CLONE(
git@github.com:SASPAC/sasjscore.git,
&dirOut,
git,
%str( ),
/home/sasjssrv/.ssh/id_ecdsa.pub,
/home/sasjssrv/.ssh/id_ecdsa
));
/*
Prepare Package Metadata
*/
data _null_;
infile CARDS4;
file "&dirOut./description.sas";
input;
if _infile_ =: 'Version:' then put "Version: &version.";
else put _infile_;
CARDS4;
Type: Package
Package: SASjsCore
Title: SAS Macros for Application Development
Version: $(PLACEHOLDER)
Author: Allan Bowe
Maintainer: 4GL Ltd
License: MIT
Encoding: UTF8
DESCRIPTION START:
The SASjs Macro Core library is a component of the SASjs framework, the
source for which is avaible here: https://github.com/sasjs
Macros are divided by:
* Macro Functions (prefix mf_)
* Macro Procedures (prefix mp_)
* Macros for Metadata (prefix mm_)
* Macros for SASjs Server (prefix ms_)
* Macros for Viya (prefix mv_)
DESCRIPTION END:
;;;;
run;
/*
Prepare Package License
*/
data _null_;
file "&dirOut./license.sas";
infile "&dir/LICENSE";
input;
put _infile_;
run;
/*
Extract Core files into MacroCore Package location
*/
data members(compress=char);
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
rc = filename(dref, "&dir.");
put dref=;
did = dopen(dref);
if did then
do i = 1 to dnum(did);
name = dread(did, i);
if name in
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
then do;
rc = filename(dref2,catx("/", "&dir.", name));
put dref2= name;
did2 = dopen(dref2);
if did2 then
do j = 1 to dnum(did2);
name2 = dread(did2, j);
path = catx("/", "&dir.", name, name2);
if "sas" = scan(name2, -1, ".") then output;
end;
rc = dclose(did2);
rc = filename(dref2);
end;
end;
rc = dclose(did);
rc = filename(dref);
keep name name2 path;
run;
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
options nosource nonotes;
data _null_;
set members;
by name notsorted;
ord + first.name;
if first.name then
do;
call execute('libname _ '
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
!! ";"
);
put @1 "./" ord z3. "_macros/";
end;
put @10 name2;
call execute("
data _null_;
infile " !! quote(strip(path)) !! ";
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
input;
select;
when (2 = trigger) put _infile_;
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
otherwise put _infile_;
end;
run;");
run;
options &temp_options.;
/*
Generate SASjsCore Package
*/
%GeneratePackage(
filesLocation=&dirOut
)
/**
* apply new version in a github action
* 1. create folder
* 2. create template yaml
* 3. replace version number
*/
%mf_mkdir(&dirout/.github/workflows)
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
data _null_;
file "&dirout/.github/workflows/release.yml";
put "name: SASjs Core Package Publish Tag";
put "on:";
put " push:";
put " branches:";
put " - main";
put "jobs:";
put " update:";
put " runs-on: ubuntu-latest";
put " steps:";
put " - uses: actions/checkout@master";
put " - name: Make Release";
put " uses: alice-biometrics/release-creator/@v1.0.5";
put " with:";
put " github_token: ${{ secrets.GH_TOKEN }}";
put " branch: main";
put " draft: false";
put " version: &version";
put " description: '&desc'";
run;
/**
* Add, Commit & Push!
*/
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
data _null_;
rc=gitfn_commit("&dirout"
,"HEAD","&sysuserid","sasjs@core"
,"FEAT: Releasing &version"
);
put rc=;
rc=git_push(
"&dirout"
,"git"
,""
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
,"/home/sasjssrv/.ssh/id_ecdsa"
);
run;
/**
@file
@brief Deploy repo as a SAS PACKAGES module
@details After every release, this program is executed to update the SASPAC
repo with the latest macros (and same version number).
The program is first compiled using sasjs compile, then executed using
sasjs run.
Requires the server to have SSH keys.
<h4> SAS Macros </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
/* get package version */
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
data _null_;
set splib.root;
call symputx('version',substr(TAG_NAME,2));
run;
/* clone the source repo */
%let dir = %sysfunc(pathname(work))/core;
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
/*
clone the target repo.
If you have issues, see: https://stackoverflow.com/questions/74082874
*/
options dlcreatedir;
%let dirOut = %sysfunc(pathname(work))/package;
libname _ "&dirOut.";
%put tgt clone rc=%sysfunc(GITFN_CLONE(
git@github.com:SASPAC/sasjscore.git,
&dirOut,
git,
%str( ),
/home/sasjssrv/.ssh/id_ecdsa.pub,
/home/sasjssrv/.ssh/id_ecdsa
));
/*
Prepare Package Metadata
*/
data _null_;
infile CARDS4;
file "&dirOut./description.sas";
input;
if _infile_ =: 'Version:' then put "Version: &version.";
else put _infile_;
CARDS4;
Type: Package
Package: SASjsCore
Title: SAS Macros for Application Development
Version: $(PLACEHOLDER)
Author: Allan Bowe
Maintainer: 4GL Ltd
License: MIT
Encoding: UTF8
DESCRIPTION START:
The SASjs Macro Core library is a component of the SASjs framework, the
source for which is avaible here: https://github.com/sasjs
Macros are divided by:
* Macro Functions (prefix mf_)
* Macro Procedures (prefix mp_)
* Macros for Metadata (prefix mm_)
* Macros for SASjs Server (prefix ms_)
* Macros for Viya (prefix mv_)
DESCRIPTION END:
;;;;
run;
/*
Prepare Package License
*/
data _null_;
file "&dirOut./license.sas";
infile "&dir/LICENSE";
input;
put _infile_;
run;
/*
Extract Core files into MacroCore Package location
*/
data members(compress=char);
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
rc = filename(dref, "&dir.");
put dref=;
did = dopen(dref);
if did then
do i = 1 to dnum(did);
name = dread(did, i);
if name in
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
then do;
rc = filename(dref2,catx("/", "&dir.", name));
put dref2= name;
did2 = dopen(dref2);
if did2 then
do j = 1 to dnum(did2);
name2 = dread(did2, j);
path = catx("/", "&dir.", name, name2);
if "sas" = scan(name2, -1, ".") then output;
end;
rc = dclose(did2);
rc = filename(dref2);
end;
end;
rc = dclose(did);
rc = filename(dref);
keep name name2 path;
run;
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
options nosource nonotes;
data _null_;
set members;
by name notsorted;
ord + first.name;
if first.name then
do;
call execute('libname _ '
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
!! ";"
);
put @1 "./" ord z3. "_macros/";
end;
put @10 name2;
call execute("
data _null_;
infile " !! quote(strip(path)) !! ";
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
input;
select;
when (2 = trigger) put _infile_;
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
otherwise put _infile_;
end;
run;");
run;
options &temp_options.;
/*
Generate SASjsCore Package
*/
%GeneratePackage(
filesLocation=&dirOut
)
/**
* apply new version in a github action
* 1. create folder
* 2. create template yaml
* 3. replace version number
*/
%mf_mkdir(&dirout/.github/workflows)
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
data _null_;
file "&dirout/.github/workflows/release.yml";
put "name: SASjs Core Package Publish Tag";
put "on:";
put " push:";
put " branches:";
put " - main";
put "jobs:";
put " update:";
put " runs-on: ubuntu-latest";
put " steps:";
put " - uses: actions/checkout@master";
put " - name: Make Release";
put " uses: alice-biometrics/release-creator/@v1.0.5";
put " with:";
put " github_token: ${{ secrets.GH_TOKEN }}";
put " branch: main";
put " draft: false";
put " version: &version";
put " description: '&desc'";
run;
/**
* Add, Commit & Push!
*/
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
data _null_;
rc=gitfn_commit("&dirout"
,"HEAD","&sysuserid","sasjs@core"
,"FEAT: Releasing &version"
);
put rc=;
rc=git_push(
"&dirout"
,"git"
,""
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
,"/home/sasjssrv/.ssh/id_ecdsa"
);
run;

View File

@@ -539,7 +539,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
@@ -560,7 +560,25 @@ data _null_;
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' put ",""SYSENCODING"" : ""&sysencoding"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); ';
put ' put '',"SYSHOSTINFOLONG" : '' SYSHOSTINFOLONG; ';
@@ -576,7 +594,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';

View File

@@ -22,7 +22,7 @@
@param [in] uid= (0) Provide the userid on which to filter
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
list of groups. Format:
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|NAME:$32.|DESCRIPTION:$256.|GROUPID:best.|
|---|---|---|
|`SomeGroup `|`A group `|`1`|
|`Another Group`|`this is a different group`|`2`|
@@ -58,7 +58,7 @@
%if %sysget(MODE)=desktop %then %do;
/* groups api does not exist in desktop mode */
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
name="&sysuserid";
description="&sysuserid (group - desktop mode)";
groupid=1;
@@ -114,7 +114,7 @@ libname &libref JSON fileref=&fref1;
%if "&user"="0" and "&uid"="0" %then %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..root;
drop ordinal_root;
@@ -122,7 +122,7 @@ libname &libref JSON fileref=&fref1;
%end;
%else %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..groups;
drop ordinal_:;

View File

@@ -39,8 +39,9 @@
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_chop.sas
**/
@@ -153,7 +154,10 @@ run;
run;
%end;
filename &outref temp lrecl=32767;
%local resp_path;
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
filename &outref "&resp_path" lrecl=32767;
/* prepare request*/
proc http method='POST' headerin=&authref in=&mainref out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
@@ -161,6 +165,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
debug level=2;
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
@@ -176,11 +181,22 @@ or &mdebug=1
options &optval;
%if &outlogds ne _null_ or &mdebug=1 %then %do;
%local dumplib;
%let dumplib=%mf_getuniquelibref();
libname &dumplib json fileref=&outref;
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("&resp_path"
,matchvar=matchstr
,keep=LAST
,matchpoint=END
,outfile="&chopout"
,mdebug=&mdebug
)
data &outlogds;
set &dumplib..log;
infile "&chopout" lrecl=2000;
length line $2000;
line=_infile_;
%if &mdebug=1 %then %do;
putlog line=;
%end;

View File

@@ -108,47 +108,34 @@ run;
)
/* SASjs services have the _webout embedded in wrapper JSON */
/* Files can also be very large - so use a dedicated macro to chop it out */
%local matchstr1 matchstr2 ;
%let matchstr1={"status":"success","_webout":{;
%let matchstr2=},"log":[{;
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
/* chop out JSON section */
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("%sysfunc(pathname(&fref1,F))"
,matchvar=matchstr1
,keep=LAST
,matchpoint=END
,offset=-1
,outfile="&chopout1"
,mdebug=&mdebug
)
%mp_chop("&chopout1"
,matchvar=matchstr2
,matchvar=matchstr
,keep=FIRST
,matchpoint=START
,offset=1
,outfile="&chopout2"
,offset=-1
,outfile="&chopout"
,mdebug=&mdebug
)
%if &outlib ne 0 %then %do;
libname &outlib json "&chopout2";
libname &outlib json "&chopout";
%end;
%if &outref ne 0 %then %do;
filename &outref "&chopout2";
filename &outref "&chopout";
%end;
%if &mdebug=0 %then %do;
filename &webref clear;
filename &fref1 clear;
filename &fref2 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend ms_testservice;
%mend ms_testservice;

View File

@@ -141,7 +141,7 @@
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file &fref mod encoding='utf-8' termstr=lf;
@@ -162,7 +162,25 @@
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSENCODING"" : ""&sysencoding"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
@@ -178,7 +196,25 @@
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;

View File

@@ -17,4 +17,24 @@
%mp_assert(
iftrue=(%mf_existvar(sashelp.class,isjustanumber)=0),
desc=Checking non existing var does not exist
)
data work.lockcheck;
a=1;
output;
stop;
run;
%mp_assert(
iftrue=(%mf_existvar(work.lockcheck,)=0),
desc=Checking non-provided var does not exist
)
proc sql;
update work.lockcheck set a=2;
%mp_assert(
iftrue=(&syscc=0),
desc=Checking the lock was released,
outds=work.test_results
)

View File

@@ -0,0 +1,20 @@
/**
@file
@brief Testing mf_getgitbranch.sas macro
<h4> SAS Macros </h4>
@li mf_getgitbranch.sas
@li mp_assert.sas
**/
/* grab core repo */
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&gitdir));
%mp_assert(
iftrue=(%mf_getgitbranch(&gitdir)=main),
desc=Checking correct branch was obtained,
outds=work.test_results
)

View File

@@ -0,0 +1,40 @@
/**
@file
@brief Testing mf_readfile.sas macro
<h4> SAS Macros </h4>
@li mf_readfile.sas
@li mf_writefile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let f=&sasjswork/myfile.txt;
%mf_writefile(&f,l1=some content,l2=more content)
data _null_;
infile "&f";
input;
putlog _infile_;
run;
%mp_assert(
iftrue=(&syscc=0),
desc=Check code ran without errors,
outds=work.test_results
)
/* test for scope leakage */
%global result;
%mp_assertscope(SNAPSHOT)
%put %mf_readfile(&f);
%mp_assertscope(COMPARE)
/* test result */
%mp_assert(
iftrue=(%mf_readfile(&f)=some content),
desc=Checking first line was ingested successfully,
outds=work.test_results
)

View File

@@ -7,23 +7,35 @@
@li mp_assertcols.sas
@li mp_assertcolvals.sas
@li mp_assertdsobs.sas
@li mp_assertscope.sas
**/
/* valid filter */
%mp_getcols(sashelp.airline,outds=work.info)
/* make some data */
proc sql;
create table work.src(
SOME_DATETIME float format=datetime19.,
SOME_CHAR char(16),
SOME_NUM num,
SOME_TIME num format=time8.,
SOME_DATE num format=date9.
);
/* run macro, checking for scope leakage */
%mp_assertscope(SNAPSHOT)
%mp_getcols(work.src,outds=work.info)
%mp_assertscope(COMPARE)
%mp_assertdsobs(work.info,
desc=Has 3 records,
test=EQUALS 3,
desc=Has 5 records,
test=EQUALS 5,
outds=work.test_results
)
data work.check;
length val $10;
do val='NUMERIC','DATE','CHARACTER';
do val='NUMERIC','DATE','CHARACTER','DATETIME','TIME';
output;
end;
run;

View File

@@ -0,0 +1,32 @@
/**
@file
@brief Testing mp_gitlog.sas macro
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_gitlog.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* grab core repo */
%let gitdir=%sysfunc(pathname(work))/core;
%let repo=https://github.com/sasjs/core;
%put source clone rc=%sysfunc(GITFN_CLONE(&repo,&gitdir));
%mp_assertscope(SNAPSHOT)
%mp_gitlog(&gitdir,outds=work.test1)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(&syscc=0),
desc=Regular test works,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test1)>1000),
desc=output has gt 1000 rows,
outds=work.test_results
)

View File

@@ -4,8 +4,10 @@
<h4> SAS Macros </h4>
@li mp_lockanytable.sas
@li mp_assert.sas
@li mp_assertcols.sas
@li mp_assertcolvals.sas
@li mp_assertscope.sas
@li mp_coretable.sas
**/
@@ -61,3 +63,18 @@ run;
desc=Ref is captured in unlock,
test=ANYVAL
)
/* attempt unlock of a table that was never locked */
%mp_lockanytable(UNLOCK,lib=no,ds=doesnotexist,ref=bye, ctl_ds=work.controller)
%mp_assert(
iftrue=(&syscc=0),
desc=Ability to unlock a table that was never locked,
outds=work.test_results
)
/* test for macro variable scope leakage */
%mp_assertscope(SNAPSHOT)
%mp_lockanytable(LOCK,lib=tmp,ds=testscope,ref=This Ref, ctl_ds=work.controller)
%mp_assertscope(COMPARE)

View File

@@ -4,7 +4,7 @@
@brief Testing mv_jobflow macro
@details One of the remote jobs aborts with syscc>0 - test to
make sure this comes back to the calling session
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_createjob.sas

View File

@@ -3,7 +3,7 @@
@brief Testing mv_jobflow macro
@details All jobs complete successfully with syscc = 0 - test to
make sure this comes back to the calling session
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_createjob.sas

View File

@@ -4,7 +4,7 @@
@brief Testing mv_registerclient.sas macro
@details Tests for successful registration. For this to work, the test
account must be an admin.
<h4> SAS Macros </h4>
@li mf_getuniquename.sas
@li mp_assertcolvals.sas

View File

@@ -1,10 +1,9 @@
/**
@file
@brief Testing mv_registerclient.sas macro
@details Tests for unsuccessful registration. To do this, overrides are
applied for the mf_loc.sas and mp_abort.sas macros.
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_registerclient.sas

View File

@@ -1,60 +1,60 @@
/**
@file mfv_existsashdat.sas
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
@details Can be used in open code, eg as follows:
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
The function uses `dosubl()` to run the `table.fileinfo` action, for the
specified library, filtering for `*.sashdat` tables. The results are stored
in a WORK table (&outprefix._&lib). If that table already exists, it is
queried instead, to avoid the dosubl() performance hit.
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
before running the function.
@param libds library.dataset
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
tables to improve subsequent query performance. This reference is a prefix
and is converted to `&prefix._{libref}`
@return output returns 1 or 0
@version 0.2
@author Mathieu Blauw
**/
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
);
%local rc dsid name lib ds;
%let lib=%upcase(%scan(&libds,1,'.'));
%let ds=%upcase(%scan(&libds,-1,'.'));
/* if table does not exist, create it */
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
%let rc=%sysfunc(dosubl(%nrstr(
/* Read in table list (once per &lib per session) */
proc cas;
table.fileinfo result=source_list /caslib="&lib";
val=findtable(source_list);
saveresult val dataout=&outprefix._&lib;
quit;
/* Only keep name, without file extension */
data &outprefix._&lib;
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
Name=upcase(scan(Name,1,'.'));
run;
)));
%end;
/* Scan table for hdat existence */
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
%syscall set(dsid);
%let rc = %sysfunc(fetch(&dsid));
%let rc = %sysfunc(close(&dsid));
/* Return result */
%if "%trim(&name)"="%trim(&ds)" %then 1;
%else 0;
%mend mfv_existsashdat;
/**
@file mfv_existsashdat.sas
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
@details Can be used in open code, eg as follows:
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
The function uses `dosubl()` to run the `table.fileinfo` action, for the
specified library, filtering for `*.sashdat` tables. The results are stored
in a WORK table (&outprefix._&lib). If that table already exists, it is
queried instead, to avoid the dosubl() performance hit.
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
before running the function.
@param libds library.dataset
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
tables to improve subsequent query performance. This reference is a prefix
and is converted to `&prefix._{libref}`
@return output returns 1 or 0
@version 0.2
@author Mathieu Blauw
**/
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
);
%local rc dsid name lib ds;
%let lib=%upcase(%scan(&libds,1,'.'));
%let ds=%upcase(%scan(&libds,-1,'.'));
/* if table does not exist, create it */
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
%let rc=%sysfunc(dosubl(%nrstr(
/* Read in table list (once per &lib per session) */
proc cas;
table.fileinfo result=source_list /caslib="&lib";
val=findtable(source_list);
saveresult val dataout=&outprefix._&lib;
quit;
/* Only keep name, without file extension */
data &outprefix._&lib;
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
Name=upcase(scan(Name,1,'.'));
run;
)));
%end;
/* Scan table for hdat existence */
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
%syscall set(dsid);
%let rc = %sysfunc(fetch(&dsid));
%let rc = %sysfunc(close(&dsid));
/* Return result */
%if "%trim(&name)"="%trim(&ds)" %then 1;
%else 0;
%mend mfv_existsashdat;

View File

@@ -743,7 +743,25 @@ data _null_;
put ' put '',"SYS_JES_JOB_URI" : '' SYS_JES_JOB_URI ; ';
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
put ' put ",""SYSCC"" : ""&syscc"" "; ';
put ' syserrortext=cats(''"'',tranwrd(symget(''syserrortext''),''"'',''\"''),''"''); ';
put ' syserrortext=cats(symget(''syserrortext'')); ';
put ' if findc(syserrortext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syserrortext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syserrortext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syserrortext=cats(''"'',syserrortext,''"''); ';
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
@@ -756,7 +774,25 @@ data _null_;
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
put ' put '',"SYSVLONG" : '' sysvlong; ';
put ' syswarningtext=cats(''"'',tranwrd(symget(''syswarningtext''),''"'',''\"''),''"''); ';
put ' syswarningtext=cats(symget(''syswarningtext'')); ';
put ' if findc(syswarningtext,''"\''!!''0A0D09000E0F010210111A''x) then do; ';
put ' syswarningtext=''"''!!trim( ';
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\x1A/\\u001A/'',-1, /* SUB */ ';
put ' prxchange(''s/\\/\\\\/'',-1,syswarningtext) ';
put ' )))))))))))))!!''"''; ';
put ' end; ';
put ' else syswarningtext=cats(''"'',syswarningtext,''"''); ';
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
put ' length memsize $32; ';

View File

@@ -204,7 +204,25 @@
put ',"SYS_JES_JOB_URI" : ' SYS_JES_JOB_URI ;
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSCC"" : ""&syscc"" ";
syserrortext=cats('"',tranwrd(symget('syserrortext'),'"','\"'),'"');
syserrortext=cats(symget('syserrortext'));
if findc(syserrortext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syserrortext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syserrortext)
)))))))))))))!!'"';
end;
else syserrortext=cats('"',syserrortext,'"');
put ',"SYSERRORTEXT" : ' syserrortext;
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" ";
@@ -217,7 +235,25 @@
put ",""SYSUSERID"" : ""&sysuserid"" ";
sysvlong=quote(trim(symget('sysvlong')));
put ',"SYSVLONG" : ' sysvlong;
syswarningtext=cats('"',tranwrd(symget('syswarningtext'),'"','\"'),'"');
syswarningtext=cats(symget('syswarningtext'));
if findc(syswarningtext,'"\'!!'0A0D09000E0F010210111A'x) then do;
syswarningtext='"'!!trim(
prxchange('s/"/\\"/',-1, /* double quote */
prxchange('s/\x0A/\n/',-1, /* new line */
prxchange('s/\x0D/\r/',-1, /* carriage return */
prxchange('s/\x09/\\t/',-1, /* tab */
prxchange('s/\x00/\\u0000/',-1, /* NUL */
prxchange('s/\x0E/\\u000E/',-1, /* SS */
prxchange('s/\x0F/\\u000F/',-1, /* SF */
prxchange('s/\x01/\\u0001/',-1, /* SOH */
prxchange('s/\x02/\\u0002/',-1, /* STX */
prxchange('s/\x10/\\u0010/',-1, /* DLE */
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
prxchange('s/\x1A/\\u001A/',-1, /* SUB */
prxchange('s/\\/\\\\/',-1,syswarningtext)
)))))))))))))!!'"';
end;
else syswarningtext=cats('"',syswarningtext,'"');
put ',"SYSWARNINGTEXT" : ' syswarningtext;
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
length memsize $32;