mirror of
https://github.com/sasjs/core.git
synced 2025-12-24 19:51:19 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c58b5c7a52 | ||
|
|
22c7e5b4dd | ||
|
|
244171f8c4 | ||
|
|
fd765e2d68 | ||
| 840cb5ef44 | |||
| 918ce96fce | |||
| f1712c34e8 | |||
| 11ec20b472 | |||
| f42f111462 | |||
| 907725c5ba | |||
| 95b78b91e1 | |||
| e4771b9c14 | |||
| ba8190883e | |||
|
|
32dd057e83 | ||
|
|
7471bd42a4 | ||
|
|
702a4ecd3a | ||
|
|
5da97295ff | ||
|
|
dc556bdef0 | ||
|
|
111731bf35 | ||
|
|
2c526cf9dd | ||
|
|
660e02193f | ||
|
|
00b4dee86e | ||
|
|
3913825c22 | ||
|
|
0f143d603b | ||
|
|
f1d5fa2c0a | ||
|
|
a88689428f | ||
|
|
8843fa8bfc | ||
|
|
22d046cf5c | ||
|
|
29e3eb34aa | ||
|
|
1af52a6683 | ||
|
|
fc0c96dd94 | ||
|
|
b9c4882553 | ||
|
|
011b2b185c | ||
|
|
dbc23550ac | ||
|
|
8910840ccc | ||
|
|
4ef571032d | ||
|
|
e01cd8cd16 | ||
|
|
00628ec78a | ||
|
|
f4e6a487f3 | ||
|
|
b7afecdf81 | ||
|
|
19eb348f0e | ||
|
|
f420ac2abf | ||
|
|
7edec1ad8a | ||
|
|
62d7bce249 | ||
|
|
fe6c9a793b | ||
|
|
8e13943356 | ||
|
|
04df9600e0 | ||
|
|
e2b0aabfa4 | ||
|
|
c52a623630 | ||
|
|
cf348e8016 |
@@ -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
25
.github/vpn/config.ovpn
vendored
Normal 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
|
||||
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@@ -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
|
||||
|
||||
|
||||
|
||||
35
.github/workflows/run-tests.yml
vendored
35
.github/workflows/run-tests.yml
vendored
@@ -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
4
.gitignore
vendored
@@ -10,4 +10,6 @@ sasjsresults/
|
||||
mc_*
|
||||
|
||||
# ignore .env files as they can contain sasjs access tokens
|
||||
*.env*
|
||||
*.env*
|
||||
|
||||
~
|
||||
|
||||
26
.sasjslint
26
.sasjslint
@@ -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
|
||||
}
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -6,5 +6,7 @@
|
||||
"editor.rulers": [
|
||||
80
|
||||
],
|
||||
"files.trimTrailingWhitespace": true
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"sasjs-for-vscode.target": "docsonly",
|
||||
"sasjs-for-vscode.isLocal": true
|
||||
}
|
||||
39
README.md
39
README.md
@@ -2,8 +2,6 @@
|
||||
[![npm package][npm-image]][npm-url]
|
||||
[![Github Workflow][githubworkflow-image]][githubworkflow-url]
|
||||

|
||||

|
||||
[](/LICENSE)
|
||||

|
||||
[](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
|
||||
[](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 -->
|
||||
[](#contributors-)
|
||||
[](#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
609
all.sas
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
0
|
||||
%end;
|
||||
|
||||
%mend mf_existfileref;
|
||||
%mend mf_existfileref;
|
||||
|
||||
@@ -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
37
base/mf_getgitbranch.sas
Normal 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
63
base/mf_readfile.sas
Normal 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 */
|
||||
@@ -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 "}" ;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
104
base/mp_gitlog.sas
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
668
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
{
|
||||
"name": "docsonly",
|
||||
"serverType": "SASJS",
|
||||
"appLoc": "dummy",
|
||||
"appLoc": "/dummy",
|
||||
"macroFolders": [
|
||||
"meta",
|
||||
"metax",
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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; ';
|
||||
|
||||
@@ -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_:;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
)
|
||||
20
tests/base/mf_getgitbranch.test.sas
Normal file
20
tests/base/mf_getgitbranch.test.sas
Normal 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
|
||||
)
|
||||
40
tests/base/mf_readfile.test.sas
Normal file
40
tests/base/mf_readfile.test.sas
Normal 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
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
32
tests/base/mp_gitlog.test.sas
Normal file
32
tests/base/mp_gitlog.test.sas
Normal 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
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; ';
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user