1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-07 09:30:06 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Allan Bowe
f0a5d89016 build.sh build on 2022-02-24:21:33:11 2022-02-24 21:33:11 +00:00
62 changed files with 972 additions and 2405 deletions

View File

@@ -117,15 +117,6 @@
"contributions": [ "contributions": [
"bug" "bug"
] ]
},
{
"login": "yabwon",
"name": "Bart Jablonski",
"avatar_url": "https://avatars.githubusercontent.com/u/9314894?v=4",
"profile": "https://github.com/yabwon",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@@ -1,12 +1,5 @@
#!/bin/bash #!/bin/bash
sasjs lint
# Ensure lint is passing
LINT=`sasjs lint`
if [[ "$LINT" != "✔ All matched files use @sasjs/lint code style!" ]]; then
echo "$LINT"
echo "To commit in spite of these warnings, use the -n parameter."
exit 1
fi
# Avoid commits to the master branch # Avoid commits to the master branch
BRANCH=`git rev-parse --abbrev-ref HEAD` BRANCH=`git rev-parse --abbrev-ref HEAD`

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [sasjs]

View File

@@ -1,7 +1,7 @@
tasks: tasks:
- init: npm install -g npm - init: |
- command: npm i nvm install --lts
- command: npm i -g @sasjs/cli npm i -g @sasjs/cli
image: image:
file: .gitpod.dockerfile file: .gitpod.dockerfile
@@ -24,4 +24,4 @@ github:
# add a "Review in Gitpod" button to pull requests (defaults to false) # add a "Review in Gitpod" button to pull requests (defaults to false)
addBadge: false addBadge: false
# add a label once the prebuild is ready to pull requests (defaults to false) # add a label once the prebuild is ready to pull requests (defaults to false)
addLabel: prebuilt-in-gitpod addLabel: prebuilt-in-gitpod

1
CNAME Normal file
View File

@@ -0,0 +1 @@
core.sasjs.io

View File

@@ -47,7 +47,7 @@ Documentation: https://core.sasjs.io
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications). This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
### FCMP library (All Platforms) #### FCMP library (All Platforms)
- Function and macro names are identical, except for special cases - Function and macro names are identical, except for special cases
- Prefixes: _mcf_ - Prefixes: _mcf_
@@ -204,7 +204,6 @@ When contributing to this library, it is therefore important to ensure that all
We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major/breaking release (v5) becomes necessary: We are currently on major release v4. Breaking changes should be marked with the [deprecated](https://www.doxygen.nl/manual/commands.html#cmddeprecated) doxygen tag. The following changes are planned when the next major/breaking release (v5) becomes necessary:
* mf_getuniquelibref.sas to have the deprecated maxtried parameter removed (no longer needed)
* mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything) * mp_testservice.sas to be renamed as mp_execute.sas (as it doesn't actually test anything)
* `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed) * `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed)
* mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues. * mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues.
@@ -217,19 +216,11 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
![](https://starchart.cc/sasjs/core.svg) ![](https://starchart.cc/sasjs/core.svg)
## Other SAS Repositories
The following repositories are also worth checking out:
* [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros)
* [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs)
* [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros)
* [scottbass/sas](https://github.com/scottbass/SAS)
* [yabwon/sas_packages](https://github.com/yabwon/SAS_PACKAGES)
## Contributors ✨ ## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-) [![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END --> <!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -250,7 +241,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<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/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/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/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>
</tr> </tr>
</table> </table>

1320
all.sas

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +0,0 @@
/**
@file
@brief Deletes a physical file, if it exists
@details Usage:
%mf_writefile(&sasjswork/myfile.txt,l1=some content)
%mf_deletefile(&sasjswork/myfile.txt)
%mf_deletefile(&sasjswork/myfile.txt)
@param filepath Full path to the target file
@returns The return code from the fdelete() invocation
<h4> Related Macros </h4>
@li mf_deletefile.test.sas
@li mf_writefile.sas
@version 9.2
@author Allan Bowe
**/
%macro mf_deletefile(file
)/*/STORE SOURCE*/;
%local rc fref;
%let rc= %sysfunc(filename(fref,&file));
%if %sysfunc(fdelete(&fref)) ne 0 %then %put %sysfunc(sysmsg());
%let rc= %sysfunc(filename(fref));
%mend mf_deletefile;

View File

@@ -9,17 +9,19 @@
%put %mf_existfeature(PROCLUA); %put %mf_existfeature(PROCLUA);
@param [in] feature The feature to detect. @param feature the feature to detect. Leave blank to list all in log.
@return output returns 1 or 0 (or -1 if not found) @return output returns 1 or 0 (or -1 if not found)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas @li mf_getplatform.sas
@version 8 @version 8
@author Allan Bowe @author Allan Bowe
**/ **/
/** @cond */ /** @cond */
%macro mf_existfeature(feature %macro mf_existfeature(feature
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let feature=%upcase(&feature); %let feature=%upcase(&feature);
@@ -27,11 +29,7 @@
%let platform=%mf_getplatform(); %let platform=%mf_getplatform();
%if &feature= %then %do; %if &feature= %then %do;
%put No feature was requested for detection; %put Supported features: PROCLUA;
%end;
%else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0;
%else 1;
%end; %end;
%else %if &feature=PROCLUA %then %do; %else %if &feature=PROCLUA %then %do;
/* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */ /* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */
@@ -45,4 +43,5 @@
%put &sysmacroname: &feature not found; %put &sysmacroname: &feature not found;
%end; %end;
%mend mf_existfeature; %mend mf_existfeature;
/** @endcond */
/** @endcond */

View File

@@ -14,44 +14,27 @@
> mclib3 > mclib3
A blank value is returned if no usable libname is determined. @param prefix= first part of libref. Remember that librefs can only be 8 characters,
so a 7 letter prefix would mean that maxtries should be 10.
@param [in] prefix= (mclib) first part of the returned libref. As librefs can @param maxtries= the last part of the libref. Provide an integer value.
be as long as 8 characters, a maximum length of 7 characters is premitted
for this prefix.
@param [in] maxtries= Deprecated parameter. Remains here to ensure a
non-breaking change. Will be removed in v5.
@version 9.2 @version 9.2
@author Allan Bowe @author Allan Bowe
**/ **/
%macro mf_getuniquelibref(prefix=mclib,maxtries=1000); %macro mf_getuniquelibref(prefix=mclib,maxtries=1000);
%local x; %local x libref;
%let x=0;
%if ( %length(&prefix) gt 7 ) %then %do; %do x=0 %to &maxtries;
%put %str(ERR)OR: The prefix parameter cannot exceed 7 characters.; %if %sysfunc(libref(&prefix&x)) ne 0 %then %do;
0 %let libref=&prefix&x;
%let rc=%sysfunc(libname(&libref,%sysfunc(pathname(work))));
%if &rc %then %put %sysfunc(sysmsg());
&prefix&x
%*put &sysmacroname: Libref &libref assigned as WORK and returned;
%return; %return;
%end; %end;
%else %if (%sysfunc(NVALID(&prefix,v7))=0) %then %do;
%put %str(ERR)OR: Invalid prefix (&prefix);
0
%return;
%end; %end;
%put unable to find available libref in range &prefix.0-&maxtries;
/* Set maxtries equal to '10 to the power of [# unused characters] - 1' */
%let maxtries=%eval(10**(8-%length(&prefix))-1);
%do x = 0 %to &maxtries;
%if %sysfunc(libref(&prefix&x)) ne 0 %then %do;
&prefix&x
%return;
%end;
%let x = %eval(&x + 1);
%end;
%put %str(ERR)OR: No usable libref in range &prefix.0-&maxtries;
%put %str(ERR)OR- Try reducing the prefix or deleting some libraries!;
0
%mend mf_getuniquelibref; %mend mf_getuniquelibref;

View File

@@ -33,8 +33,7 @@
%else %if %symexist(&metavar) %then %do; %else %if %symexist(&metavar) %then %do;
%if %length(&&&metavar)=0 %then %let user=&sysuserid; %if %length(&&&metavar)=0 %then %let user=&sysuserid;
/* sometimes SAS will add @domain extension - remove for consistency */ /* sometimes SAS will add @domain extension - remove for consistency */
/* but be sure to quote in case of usernames with commas */ %else %let user=%scan(&&&metavar,1,@);
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@));
%end; %end;
%else %let user=&sysuserid; %else %let user=&sysuserid;

View File

@@ -59,7 +59,7 @@
%goto exit_success; %goto exit_success;
%exit_err: %exit_err:
%put &abortmsg; %put %str(ERR)OR: &abortmsg;
%mf_abort(iftrue=(&mabort ne SOFT), %mf_abort(iftrue=(&mabort ne SOFT),
mac=mf_verifymacvars, mac=mf_verifymacvars,
msg=%str(&abortmsg) msg=%str(&abortmsg)

View File

@@ -85,7 +85,7 @@
%end; %end;
/* Stored Process Server web app context */ /* Stored Process Server web app context */
%if %symexist(_METAFOLDER) %if %symexist(_metaperson)
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
@@ -161,14 +161,12 @@
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
data _null_; data _null_;
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg syswarningtext syserrortext $32767 ; length msg $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=symget('msg'); msg=symget('msg');
%if &logline>0 %then %do; %if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg')); msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end; %end;
/* escape the escapes */
msg=tranwrd(msg,'\','\\');
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */
@@ -262,4 +260,4 @@
%end; %end;
%mend mp_abort; %mend mp_abort;
/** @endcond */ /** @endcond */

View File

@@ -74,8 +74,7 @@
outds=work.test_results outds=work.test_results
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local ds test_result test_comments del add mod ilist; %local ds test_result test_comments del add mod ilist;
%let ilist=%upcase(&sasjs_prefix._FUNCTIONS SYS_PROCHTTP_STATUS_CODE %let ilist=%upcase(&sasjs_prefix._FUNCTIONS &ignorelist);
SYS_PROCHTTP_STATUS_CODE SYS_PROCHTTP_STATUS_PHRASE &ignorelist);
/** /**
* this sets up the global vars, it will also enter STRICT mode. If this * this sets up the global vars, it will also enter STRICT mode. If this
@@ -90,7 +89,7 @@
create table &scopeds as create table &scopeds as
select name,offset,value select name,offset,value
from dictionary.macros from dictionary.macros
where scope="&scope" and upcase(name) not in (%mf_getquotedstr(&ilist)) where scope="&scope" and name not in (%mf_getquotedstr(&ilist))
order by name,offset; order by name,offset;
%end; %end;
%else %if &action=COMPARE %then %do; %else %if &action=COMPARE %then %do;
@@ -104,9 +103,7 @@
%let ds=&syslast; %let ds=&syslast;
proc compare proc compare base=&scopeds compare=&ds;
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds noprint;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;
@@ -144,4 +141,4 @@
drop table &ds; drop table &ds;
%end; %end;
%mend mp_assertscope; %mend mp_assertscope;

View File

@@ -94,13 +94,6 @@ data &out_ds(compress=no
%end; %end;
if rc = 0 then do; if rc = 0 then do;
did = dopen(fref); did = dopen(fref);
if did=0 then do;
putlog "NOTE: This directory is empty, or does not exist - &path";
msg=sysmsg();
put msg;
put _all_;
stop;
end;
/* attribute is OS-dependent - could be "Directory" or "Directory Name" */ /* attribute is OS-dependent - could be "Directory" or "Directory Name" */
numopts=doptnum(did); numopts=doptnum(did);
do i=1 to numopts; do i=1 to numopts;
@@ -108,6 +101,12 @@ data &out_ds(compress=no
if foption=:'Directory' then i=numopts; if foption=:'Directory' then i=numopts;
end; end;
directory=dinfo(did,foption); directory=dinfo(did,foption);
if did=0 then do;
putlog "NOTE: This directory is empty - " directory;
msg=sysmsg();
put _all_;
stop;
end;
rc = filename(fref); rc = filename(fref);
end; end;
else do; else do;
@@ -243,4 +242,4 @@ run;
proc sql; proc sql;
drop table &out_ds; drop table &out_ds;
%mend mp_dirlist; %mend mp_dirlist;

View File

@@ -48,11 +48,6 @@
outfile=0 outfile=0
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if "%substr(&sysver,1,4)"="V.04" %then %do;
%put %str(ERR)OR: Viya 4 does not support the IO library in lua;
%return;
%end;
%ml_gsubfile() %ml_gsubfile()
%mend mp_gsubfile; %mend mp_gsubfile;

View File

@@ -1,8 +1,8 @@
/** /**
@file @file
@brief Returns a unique hash for a dataset @brief Returns a unique hash for a dataset
@details Ignores metadata attributes, used only to hash values. If used to @details Ignores metadata attributes, used only to hash values. Compared
compare datasets, they must have their columns and rows in the same order. datasets must be in the same order.
%mp_hashdataset(sashelp.class,outds=myhash) %mp_hashdataset(sashelp.class,outds=myhash)
@@ -17,16 +17,13 @@
@li mf_getattrn.sas @li mf_getattrn.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mp_md5.sas @li mf_getvartype.sas
<h4> Related Files </h4>
@li mp_hashdataset.test.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@param [in] iftrue= A condition under which the macro should be executed. @param [in] iftrue= A condition under which the macro should be executed.
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This @param [out] outds= (work.mf_hashdataset) The output dataset to create. This
will contain one column (hashkey) with one observation (a $hex32. will contain one column (hashkey) with one observation (a hex32.
representation of the input hash) representation of the input hash)
|hashkey:$32.| |hashkey:$32.|
|---| |---|
@@ -38,48 +35,48 @@
%macro mp_hashdataset( %macro mp_hashdataset(
libds, libds,
outds=work._data_, outds=,
salt=, salt=,
iftrue=%str(1=1) iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local keyvar /* roll up the md5 */ %if not(%eval(%unquote(&iftrue))) %then %return;
prevkeyvar /* retain prev record md5 */
lastvar /* last var in input ds */
cvars nvars;
%if not(%eval(%unquote(&iftrue))) %then %return; %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
%put %str(WARN)ING: Dataset &libds is empty, or is not a dataset;
/* avoid naming conflict for hash key vars */ %end;
%let keyvar=%mf_getuniquename(); %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
%let prevkeyvar=%mf_getuniquename(); %put %str(ERR)OR: Dataset &libds is not a dataset;
%let lastvar=%mf_getuniquename(); %end;
%else %do;
%if %mf_getattrn(&libds,NLOBS)=0 %then %do; %local keyvar /* roll up the md5 */
data &outds; prevkeyvar /* retain prev record md5 */
length hashkey $32; lastvar /* last var in input ds */
retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)"; varlist var i;
output; /* avoid naming conflict for hash key vars */
stop; %let keyvar=%mf_getuniquename();
run; %let prevkeyvar=%mf_getuniquename();
%put &sysmacroname: Dataset &libds is empty, or is not a dataset; %let lastvar=%mf_getuniquename();
%put &sysmacroname: hashkey of &outds is based on salt (&salt) only; %let varlist=%mf_getvarlist(&libds);
%end; data &outds(rename=(&keyvar=hashkey) keep=&keyvar);
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do; length &prevkeyvar &keyvar $32;
%put %str(ERR)OR: Dataset &libds is not a dataset; retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
%end; set &libds end=&lastvar;
%else %do; /* hash should include previous row */
data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err; &keyvar=put(md5(&prevkeyvar
length &prevkeyvar &keyvar $32; /* loop every column, hashing every individual value */
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)"; %do i=1 %to %sysfunc(countw(&varlist));
set &libds end=&lastvar; %let var=%scan(&varlist,&i,%str( ));
/* hash should include previous row */ %if %mf_getvartype(&libds,&var)=C %then %do;
&keyvar=%mp_md5( !!put(md5(trim(&var)),$hex32.)
cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar, %end;
nvars=%mf_getvarlist(&libds,typefilter=N) %else %do;
); !!put(md5(trim(put(&var*1,binary64.))),$hex32.)
&prevkeyvar=&keyvar; %end;
if &lastvar then output; %end;
run; ),$hex32.);
%end; &prevkeyvar=&keyvar;
%mend mp_hashdataset; if &lastvar then output;
run;
%end;
%mend mp_hashdataset;

View File

@@ -203,15 +203,8 @@
prxchange('s/'!!'0A'x!!'/\n/',-1, prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1, prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1, prxchange('s/'!!'09'x!!'/\t/',-1,
prxchange('s/'!!'00'x!!'/\\u0000/',-1, /* NUL */
prxchange('s/'!!'0E'x!!'/\\u000E/',-1, /* SS */
prxchange('s/'!!'0F'x!!'/\\u000F/',-1, /* SF */
prxchange('s/'!!'01'x!!'/\\u0001/',-1, /* SOH */
prxchange('s/'!!'02'x!!'/\\u0002/',-1, /* STX */
prxchange('s/'!!'02'x!!'/\\u0010/',-1, /* DLE */
prxchange('s/'!!'11'x!!'/\\u0011/',-1, /* DC1 */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
))))))))))))!!'"'; )))))!!'"';
%end; %end;
%end; %end;
run; run;

View File

@@ -40,13 +40,13 @@
@li mp_abort.sas @li mp_abort.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mddl_dc_difftable.sas @li mddl_dc_difftable.sas
@li mddl_dc_locktable.sas @li mddl_dc_locktable.sas
@li mp_loadformat.test.sas @li mp_loadformat.test.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@li mp_storediffs.sas
@li mp_stackdiffs.sas @li mp_stackdiffs.sas
@@ -134,7 +134,7 @@ run;
* First, extract only relevant formats from the catalog * First, extract only relevant formats from the catalog
*/ */
proc sql noprint; proc sql noprint;
select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds; select distinct fmtname into: fmtlist separated by ' ' from &libds;
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts) %mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
@@ -144,11 +144,8 @@ select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
*/ */
%mddl_sas_cntlout(libds=&template) %mddl_sas_cntlout(libds=&template)
data &inlibds; data &inlibds;
length &delete_col $3;
if 0 then set &template; if 0 then set &template;
set &libds; set &libds;
if &delete_col='' then &delete_col='No';
fmtname=upcase(fmtname);
if missing(type) then do; if missing(type) then do;
if substr(fmtname,1,1)='$' then type='C'; if substr(fmtname,1,1)='$' then type='C';
else type='N'; else type='N';
@@ -159,6 +156,7 @@ data &inlibds;
end; end;
run; run;
/** /**
* Identify new records * Identify new records
*/ */
@@ -265,7 +263,7 @@ options ibufsize=&ibufsize;
%end; %end;
%mp_storediffs(&libcat-FC %mp_storediffs(&libcat-FC
,&base_fmts ,&inlibds
,FMTNAME START ,FMTNAME START
,delds=&outds_del ,delds=&outds_del
,modds=&outds_mod ,modds=&outds_mod
@@ -274,9 +272,6 @@ options ibufsize=&ibufsize;
,mdebug=&mdebug ,mdebug=&mdebug
) )
proc append base=&auditlibds data=&storediffs;
run;
%if &locklibds ne 0 %then %do; %if &locklibds ne 0 %then %do;
%mp_lockanytable(UNLOCK %mp_lockanytable(UNLOCK
,lib=%scan(&auditlibds,1,.) ,lib=%scan(&auditlibds,1,.)
@@ -300,4 +295,4 @@ options ibufsize=&ibufsize;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;
%put _local_; %put _local_;
%end; %end;
%mend mp_loadformat; %mend mp_loadformat;

View File

@@ -1,8 +1,7 @@
/** /**
@file @file
@brief Mechanism for locking tables to prevent parallel modifications @brief Mechanism for locking tables to prevent parallel modifications
@details Uses a control table to enable ANY table to be locked for updates @details Uses a control table to enable ANY table to be locked for updates.
(not just SAS datasets).
Only useful if every update uses the macro! Used heavily within Only useful if every update uses the macro! Used heavily within
[Data Controller for SAS](https://datacontroller.io). [Data Controller for SAS](https://datacontroller.io).
@@ -16,7 +15,7 @@
length is 200 characters. length is 200 characters.
@param [out] ctl_ds= (0) The control table which controls the actual locking. @param [out] ctl_ds= (0) The control table which controls the actual locking.
Should already be assigned and available. The definition is available by Should already be assigned and available. The definition is available by
running the mddl_dc_locktable.sas macro. running mp_coretable.sas as follows: `%mp_coretable(LOCKTABLE)`.
@param [in] loops= (25) Number of times to check for a lock. @param [in] loops= (25) Number of times to check for a lock.
@param [in] loop_secs= (1) Seconds to wait between each lock attempt @param [in] loop_secs= (1) Seconds to wait between each lock attempt

View File

@@ -54,5 +54,5 @@ put(md5(
&sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.) &sep put(md5(trim(put(ifn(missing(&var),&var,&var*1),binary64.))),$hex32.)
%let sep=!!; %let sep=!!;
%end; %end;
),$hex32.) ),hex32.)
%mend mp_md5; %mend mp_md5;

View File

@@ -1,149 +0,0 @@
/**
@file
@brief Performs a text substitution on a file
@details Performs a find and replace on a file, either in place or to a new
file. Can be used on files where lines are longer than 32767.
Works by reading in the file byte by byte, then marking the beginning and end
of each matched string, before finally doing the replace.
Full credit for this highly efficient and syntactically satisfying SAS logic
goes to [Bartosz Jabłoński](https://www.linkedin.com/in/yabwon), founder of
the [SAS Packages](https://github.com/yabwon/SAS_PACKAGES) framework.
Usage:
%let file="%sysfunc(pathname(work))/file.txt";
%let str=replace/me;
%let rep=with/this;
data _null_;
file &file;
put 'blahblah';
put "blahblah&str.blah";
put 'blahblahblah';
run;
%mp_replace(&file, findvar=str, replacevar=rep)
data _null_;
infile &file;
input;
list;
run;
Note - if you are running a version of SAS that will allow the io package in
LUA, you can also use this macro: mp_gsubfile.sas
@param infile The QUOTED path to the file on which to perform the substitution
@param findvar= Macro variable NAME containing the string to search for
@param replacevar= Macro variable NAME containing the replacement string
@param outfile= (0) Optional QUOTED path to an the adjusted output file (to
avoid overwriting the first file).
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
<h4> Related Macros </h4>
@li mp_gsubfile.test.sas
@version 9.4
@author Bartosz Jabłoński
@author Allan Bowe
**/
%macro mp_replace(infile,
findvar=,
replacevar=,
outfile=0
)/*/STORE SOURCE*/;
%local inref dttm ds1;
%let inref=%mf_getuniquefileref();
%let outref=%mf_getuniquefileref();
%if &outfile=0 %then %let outfile=&infile;
%let ds1=%mf_getuniquename(prefix=allchars);
%let ds2=%mf_getuniquename(prefix=startmark);
/* START */
%let dttm=%sysfunc(datetime());
filename &inref &infile lrecl=1 recfm=n;
data &ds1;
infile &inref;
input sourcechar $char1. @@;
format sourcechar hex2.;
run;
data &ds2;
/* set find string to length in bytes to cover trailing spaces */
length string $ %length(%superq(&findvar));
string =symget("&findvar");
drop string;
firstchar=char(string,1);
findlen=lengthm(string); /* <- for trailing bytes */
do _N_=1 to nobs;
set &ds1 nobs=nobs point=_N_;
if sourcechar=firstchar then do;
pos=1;
s=0;
do point=_N_ to min(_N_ + findlen -1,nobs);
set &ds1 point=point;
if sourcechar=char(string, pos) then s + 1;
else goto _leave_;
pos+1;
end;
_leave_:
if s=findlen then do;
START =_N_;
_N_ =_N_+ s - 1;
STOP =_N_;
output;
end;
end;
end;
stop;
keep START STOP;
run;
data &ds1;
declare hash HS(dataset:"&ds2(keep=start)");
HS.defineKey("start");
HS.defineDone();
declare hash HE(dataset:"&ds2(keep=stop)");
HE.defineKey("stop");
HE.defineDone();
do until(eof);
set &ds1 end=eof curobs =n;
start = ^HS.check(key:n);
stop = ^HE.check(key:n);
length strt $ 1;
strt =put(start,best. -L);
retain out 1;
if out then output;
if start then out=0;
if stop then out=1;
end;
stop;
keep sourcechar strt;
run;
filename &outref &outfile recfm=n;
data _null_;
length replace $ %length(%superq(&replacevar));
replace=symget("&replacevar");
file &outref;
do until(eof);
set &ds1 end=eof;
if strt ="1" then put replace char.;
else put sourcechar char1.;
end;
stop;
run;
/* END */
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
%mend mp_replace;

View File

@@ -12,7 +12,7 @@
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt) %mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
@param [in] contenttype= (TEXT) Either TEXT, ZIP, CSV, EXCEL @param [in] contenttype= (TEXTS) Either TEXT, ZIP, CSV, EXCEL
@param [in] inloc= /path/to/file.ext to be sent @param [in] inloc= /path/to/file.ext to be sent
@param [in] inref= fileref of file to be sent (if provided, overrides `inloc`) @param [in] inref= fileref of file to be sent (if provided, overrides `inloc`)
@param [in] iftrue= (1=1) Provide a condition under which to execute. @param [in] iftrue= (1=1) Provide a condition under which to execute.

110
fcmp/mcf_stpsrv_header.sas Normal file
View File

@@ -0,0 +1,110 @@
/**
@file
@brief Provides a replacement for the stpsrv_header function
@details The stpsrv_header is normally a built-in function, used to set the
headers for SAS 9 Stored Processes as documented here:
https://go.documentation.sas.com/doc/en/itechcdc/9.4/stpug/srvhead.htm
The purpose of this custom function is to provide a replacement when running
similar code as a web service against
[sasjs/server](https://github.com/sasjs/server). It operates by creating a
text file with the headers. The location of this text file is determined by
a macro variable (`sasjs_stpsrv_header_loc`) which needs to be injected into
each service by the calling process, eg:
%let sasjs_stpsrv_header_loc = C:/temp/some_uuid/stpsrv_header.txt;
Note - the function works by appending headers to the file. If multiple same-
named headers are provided, they will all be appended - the calling process
needs to pick up the last one. This will mean removing the attribute if the
final record has an empty value.
The function takes the following (positional) parameters:
| PARAMETER | DESCRIPTION |
|------------|-------------|
| name $ | name of the header attribute to create|
| value $ | value of the header attribute|
It returns 0 if successful, or -1 if an error occured.
Usage:
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/stpsrv_header.txt;
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=file.txt");
run;
data _null_;
infile "&sasjs_stpsrv_header_loc";
input;
putlog _infile_;
run;
@param [out] wrap= (NO) Choose YES to add the proc fcmp wrapper.
@param [out] lib= (work) The output library in which to create the catalog.
@param [out] cat= (sasjs) The output catalog in which to create the package.
@param [out] pkg= (utils) The output package in which to create the function.
Uses a 3 part format: libref.catalog.package
@param [out] insert_cmplib= DEPRECATED - The CMPLIB option is checked and
values inserted only if needed.
<h4> SAS Macros </h4>
@li mcf_init.sas
<h4> Related Programs </h4>
@li mcf_stpsrv_header.test.sas
@li mp_init.sas
**/
%macro mcf_stpsrv_header(wrap=NO
,insert_cmplib=DEPRECATED
,lib=WORK
,cat=SASJS
,pkg=UTILS
)/*/STORE SOURCE*/;
%local i var cmpval found;
%if %mcf_init(stpsrv_header)=1 %then %return;
%if &wrap=YES %then %do;
proc fcmp outlib=&lib..&cat..&pkg;
%end;
function stpsrv_header(name $, value $);
length loc $128 val $512;
loc=symget('sasjs_stpsrv_header_loc');
val=trim(name)!!': '!!value;
length fref $8;
rc=filename(fref,loc);
if (rc ne 0) then return( -1 );
fid = fopen(fref,'a');
if (fid = 0) then return( -1 );
rc=fput(fid, val);
rc=fwrite(fid);
rc=fclose(fid);
rc=filename(fref);
return(0);
endsub;
%if &wrap=YES %then %do;
quit;
%end;
/* insert the CMPLIB if not already there */
%let cmpval=%sysfunc(getoption(cmplib));
%let found=0;
%do i=1 %to %sysfunc(countw(&cmpval,%str( %(%))));
%let var=%scan(&cmpval,&i,%str( %(%)));
%if &var=&lib..&cat %then %let found=1;
%end;
%if &found=0 %then %do;
options insert=(CMPLIB=(&lib..&cat));
%end;
%mend mcf_stpsrv_header;

View File

@@ -13,8 +13,8 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@param [in] libref The libref (not name) of the metadata library @param libref the libref (not name) of the metadata library
@param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will @param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return silently return
@returns libname statement @returns libname statement
@@ -28,11 +28,11 @@
libref libref
,mAbort=HARD ,mAbort=HARD
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do; %if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_; data _null_;
length liburi LibName msg $200; length liburi LibName $200;
call missing(of _all_); call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi); nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do; if nobj=1 then do;
@@ -40,30 +40,7 @@
/* now try and assign it */ /* now try and assign it */
if libname("&libref",,'meta',cats('liburi="',liburi,'";')) ne 0 then do; if libname("&libref",,'meta',cats('liburi="',liburi,'";')) ne 0 then do;
putlog "&libref could not be assigned"; putlog "&libref could not be assigned";
putlog liburi=; call symputx('msg',sysmsg(),'l');
/**
* Fetch the system message for display in the abort modal. This is
* not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX.
*/
msg=sysmsg();
if msg=:'ERROR: Libref SAVE is not assigned.' then do;
msg=catx(" ",
"Could not assign %upcase(&libref).",
"Please check metadata permissions! Libname:",libname,
"Liburi:",liburi
);
end;
else if msg="ERROR: User does not have appropriate authorization "!!
"level for library SAVE."
then do;
msg=catx(" ",
"ERROR: User does not have appropriate authorization level",
"for library %upcase(&libref), libname:",libname,
"Liburi:",liburi
);
end;
call symputx('msg',msg,'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
else do; else do;
@@ -82,16 +59,20 @@
end; end;
run; run;
%put NOTE: &msg; %if &mp_abort=1 %then %do;
%mp_abort(iftrue= (&mp_abort=1)
,mac=&sysmacroname
,msg=&msg
)
%return;
%end;
%else %if %length(&msg)>2 %then %do;
%put NOTE: &msg;
%return;
%end;
%end; %end;
%else %do; %else %do;
%put NOTE: Library &libref is already assigned; %put NOTE: Library &libref is already assigned;
%end; %end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib; %mend mm_assignlib;

View File

@@ -236,15 +236,8 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -460,8 +453,7 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' /* but be sure to quote in case of usernames with commas */ '; put ' %else %let user=%scan(&&&metavar,1,@); ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';

View File

@@ -78,7 +78,6 @@ filename &fname2 clear;
%local isgone; %local isgone;
data _null_; data _null_;
length type uri $256; length type uri $256;
call missing (of _all_);
rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri); rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri);
call symputx('isgone',type,'l'); call symputx('isgone',type,'l');
run; run;

View File

@@ -49,25 +49,20 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mf_isblank.sas
@li mf_loc.sas @li mf_loc.sas
@li mm_tree.sas @li mm_tree.sas
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas @li mp_abort.sas
@param metaloc= the metadata folder to export
@param [in] metaloc= the metadata folder to export @param secureref= fileref containing the username / password (should point to
@param [in] secureref= fileref containing the username / password (should a file in a secure location). Leave blank to substitute $bash type vars.
point to a file in a secure location). Leave blank to substitute $bash vars. @param outref= fileref to which to write the command
@param [in] excludevars= (0) A space seperated list of macro variable names, @param cmdoutloc= the directory to which the command will write the SPK
each of which contains a value that should be used to filter the output (default=WORK)
objects. @param cmdoutname= the name of the spk / log files to create (will be
@param [out] outref= fileref to which to write the command identical just with .spk or .log extension)
@param [out] cmdoutloc= (%sysfunc(pathname(work))) The directory to which the
command will write the SPK
@param [out] cmdoutname= (mmxport) The name of the spk / log files to create
(will be identical just with .spk or .log extension)
@version 9.4 @version 9.4
@author Allan Bowe @author Allan Bowe
@@ -76,7 +71,6 @@
%macro mm_spkexport(metaloc= %macro mm_spkexport(metaloc=
,secureref= ,secureref=
,excludevars=0
,outref= ,outref=
,cmdoutloc=%sysfunc(pathname(work)) ,cmdoutloc=%sysfunc(pathname(work))
,cmdoutname=mmxport ,cmdoutname=mmxport
@@ -88,7 +82,7 @@
%end; %end;
/* set creds */ /* set creds */
%local mmxuser mmxpath i var; %local mmxuser mmxpath;
%let mmxuser=$1; %let mmxuser=$1;
%let mmxpass=$2; %let mmxpass=$2;
%if %mf_isblank(&secureref)=0 %then %do; %if %mf_isblank(&secureref)=0 %then %do;
@@ -96,51 +90,35 @@
%end; %end;
/* setup metadata connection options */ /* setup metadata connection options */
%local host port platform_object_path ds; %local host port platform_object_path connx_string;
%let host=%sysfunc(getoption(metaserver)); %let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport)); %let port=%sysfunc(getoption(metaport));
%let platform_object_path=%mf_loc(POF); %let platform_object_path=%mf_loc(POF);
%let ds=%mf_getuniquename(prefix=spkexportable);
%mm_tree(root=%str(&metaloc),types=EXPORTABLE ,outds=&ds) %let connx_string=%str(-host &host -port &port -user &mmxuser %trim(
)-password &mmxpass);
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=exportable)
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref(); %if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
data _null_; data _null_;
set &ds end=last; set exportable end=last;
file &outref lrecl=32767; file &outref lrecl=32767;
length str $32767; length str $32767;
if _n_=1 then do; if _n_=1 then do;
put "# Script generated by &sysuserid on %sysfunc(datetime(),datetime19.)";
put "cd ""&platform_object_path"" \"; put "cd ""&platform_object_path"" \";
put "; ./ExportPackage -host &host -port &port -user &mmxuser \"; put "; ./ExportPackage &connx_string -disableX11 \";
put " -disableX11 -password &mmxpass \"; put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
end; end;
/* exclude particular patterns from the exported SPK */
%if "&excludevars" ne "0" %then %do;
%do i=1 %to %sysfunc(countw(&excludevars));
%let var=%scan(&excludevars,&i);
if _n_=1 then do;
length excludestr&i $1000;
retain excludestr&i;
excludestr&i=symget("&var");
putlog excludestr&i=;
putlog path=;
end;
if index(path,cats(excludestr&i))=0 and index(name,cats(excludestr&i))=0;
%end;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%end;
str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \'); str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \');
put str; put str;
if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 "; if last then put " -log ""&cmdoutloc/&cmdoutname..log"" 2>&1 ";
run; run;
%mp_abort(iftrue= (&syscc ne 0) %mp_abort(iftrue= (&syscc ne 0)
,mac=mm_spkexport ,mac=&sysmacroname
,msg=%str(syscc=&syscc) ,msg=%str(syscc=&syscc)
) )
%mend mm_spkexport; %mend mm_spkexport;

2
package-lock.json generated
View File

@@ -7,7 +7,7 @@
"name": "@sasjs/core", "name": "@sasjs/core",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@sasjs/cli": "3.6.0", "@sasjs/cli": "^3.6.0",
"@sasjs/core": "4.4.7" "@sasjs/core": "4.4.7"
} }
}, },

View File

@@ -33,7 +33,7 @@
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true" "prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
}, },
"devDependencies": { "devDependencies": {
"@sasjs/cli": "3.6.0", "@sasjs/cli": "^3.6.0",
"@sasjs/core": "4.4.7" "@sasjs/core": "4.4.7"
} }
} }

View File

@@ -4,8 +4,11 @@
"base", "base",
"ddl", "ddl",
"fcmp", "fcmp",
"lua", "meta",
"metax",
"server", "server",
"viya",
"lua",
"tests/crossplatform", "tests/crossplatform",
"tests/ddl" "tests/ddl"
], ],
@@ -36,9 +39,14 @@
}, },
"appLoc": "/Public/temp/macrocore", "appLoc": "/Public/temp/macrocore",
"macroFolders": [ "macroFolders": [
"viya",
"tests/viyaonly" "tests/viyaonly"
], ],
"programFolders": [],
"binaryFolders": [],
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
},
"contextName": "SAS Job Execution compute context" "contextName": "SAS Job Execution compute context"
}, },
{ {
@@ -50,8 +58,6 @@
}, },
"appLoc": "/Shared Data/temp/macrocore", "appLoc": "/Shared Data/temp/macrocore",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"tests/sas9only" "tests/sas9only"
], ],
"programFolders": [], "programFolders": [],
@@ -65,49 +71,23 @@
}, },
{ {
"name": "server", "name": "server",
"serverUrl": "", "serverUrl": "https://sas.analytium.co.uk:5000",
"serverType": "SASJS", "serverType": "SASJS",
"httpsAgentOptions": { "appLoc": "/Shared Data/temp/macrocore",
"allowInsecureRequests": false
},
"appLoc": "/sasjs/core",
"macroFolders": [ "macroFolders": [
"server",
"tests/serveronly" "tests/serveronly"
], ],
"programFolders": [],
"binaryFolders": [],
"deployConfig": { "deployConfig": {
"deployServicePack": true, "deployServicePack": true
"deployScripts": []
} }
}, },
{ {
"name": "docsonly", "name": "docsonly",
"serverType": "SAS9", "serverType": "SAS9",
"appLoc": "dummy",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"server",
"viya",
"tests/sas9only", "tests/sas9only",
"tests/viyaonly" "tests/viyaonly"
] ]
},
{
"name": "viya4",
"serverUrl": "https://azureuse011059.my-trials.sas.com",
"serverType": "SASVIYA",
"appLoc": "/Public/temp/macrocore",
"macroFolders": [
"viya",
"tests/viyaonly"
],
"deployConfig": {
"deployServicePack": true
},
"contextName": "SAS Job Execution compute context"
} }
] ]
} }

View File

@@ -1,98 +0,0 @@
/**
@file
@brief Creates a file on SASjs Drive
@details Creates a file on SASjs Drive. To use the file as a Stored Program,
it must have a ".sas" extension.
Example:
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
%ms_createfile(/some/stored/program.sas, inref=stpcode)
@param [in] driveloc The full path to the file in SASjs Drive
@param [in] inref= (0) The fileref containing the file to create.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
**/
%macro ms_createfile(driveloc
,inref=0
,mdebug=0
);
%local fname0 fname1 fname2 boundary fname statcd msg;
%let fname0=%mf_getuniquefileref();
%let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
%let boundary=%mf_getuniquename();
data _null_;
file &fname0 termstr=crlf;
infile &inref end=eof;
if _n_ = 1 then do;
put "--&boundary.";
put 'Content-Disposition: form-data; name="filePath"';
put ;
put "&driveloc";
put "--&boundary";
put 'Content-Disposition: form-data; name="file"; filename="ignore.sas"';
put "Content-Type: text/plain";
put ;
end;
input;
put _infile_; /* add the actual file to be sent */
if eof then do;
put ;
put "--&boundary--";
end;
run;
data _null_;
file &fname1;
put "Content-Type: multipart/form-data; boundary=&boundary";
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fname0;
input;
put _infile_;
data _null_;
infile &fname1;
input;
put _infile_;
run;
%end;
proc http method='POST' in=&fname0 headerin=&fname1 out=&fname2
url="&_sasjs_apiserverurl/SASjsApi/drive/file";
%if &mdebug=1 %then %do;
debug level=1;
%end;
run;
%let statcd=0;
data _null_;
infile &fname2;
input;
putlog _infile_;
if _infile_='{"status":"success"}' then call symputx('statcd',1,'l');
else call symputx('msg',_infile_,'l');
run;
%mp_abort(
iftrue=(&statcd=0)
,mac=ms_createfile.sas
,msg=%superq(msg)
)
%mend ms_createfile;

View File

@@ -1,35 +0,0 @@
/**
@file
@brief Deletes a file from SASjs Drive
@details Deletes a file from SASjs Drive, if it exists.
Example:
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
%ms_createfile(/some/stored/program.sas, inref=stpcode)
%ms_deletefile(/some/stored/program.sas)
@param [in] driveloc The full path to the file in SASjs Drive
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
**/
%macro ms_deletefile(driveloc
,mdebug=0
);
proc http method='DELETE'
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%mend ms_deletefile;

View File

@@ -1,41 +0,0 @@
/**
@file
@brief Gets a file from SASjs Drive
@details Fetches a file on SASjs Drive and stores it in the output fileref.
Example:
%ms_getfile(/some/stored/file.ext, outref=myfile)
@param [in] driveloc The full path to the file in SASjs Drive
@param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
**/
%macro ms_getfile(driveloc
,outref=msgetfil
,mdebug=0
);
/* use the recfm in a separate fileref to avoid issues with subsequent reads */
%local binaryfref floc;
%let binaryfref=%mf_getuniquefileref();
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
filename &outref "&floc";
filename &binaryfref "&floc" recfm=n;
proc http method='GET' out=&binaryfref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
filename &binaryfref clear;
%mend ms_getfile;

View File

@@ -1,77 +0,0 @@
/**
@file
@brief Executes a SASjs Server Stored Program
@details Runs a Stored Program (using POST method) and extracts the webout and
log from the response JSON.
Example:
%ms_runstp(/some/stored/program
,debug=131
,outref=weboot
)
@param [in] pgm The full path to the Stored Program in SASjs Drive (_program
parameter)
@param [in] debug= (131) The value to supply to the _debug URL parameter
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@param [out] outref= (outweb) The output fileref to contain the response JSON
(will be created using temp engine)
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mp_abort.sas
**/
%macro ms_runstp(pgm
,debug=131
,outref=outweb
,mdebug=0
);
%local dbg fname1;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%let fname1=%mf_getuniquefileref();
%mp_abort(iftrue=("&pgm"="")
,mac=&sysmacroname
,msg=%str(Program not provided)
)
data _null_;
file &fname1;
infile "&_sasjs_tokenfile";
input;
put 'Authorization: Bearer' _infile_;
run;
filename &outref temp;
/* prepare request*/
proc http method='POST' headerin=&fname1 out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1 %then %do;
data _null_;infile &outref;input;putlog _infile_;run;
%end;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%if &mdebug=1 %then %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%else %do;
/* clear refs */
filename &fname1 clear;
%end;
%mend ms_runstp;

View File

@@ -114,7 +114,6 @@
data _null_; data _null_;
set &tempds; set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */ if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');

View File

@@ -0,0 +1,39 @@
/**
@file
@brief Testing mcf_stpsrv_header macro
<h4> SAS Macros </h4>
@li mcf_stpsrv_header.sas
@li mp_assert.sas
**/
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/stpsrv_header.txt;
%mcf_stpsrv_header(wrap=YES, insert_cmplib=YES)
data _null_;
rc=stpsrv_header('Content-type','application/text');
rc=stpsrv_header('Content-disposition',"attachment; filename=file.txt");
run;
%let test1=FAIL;
%let test2=FAIL;
data _null_;
infile "&sasjs_stpsrv_header_loc";
input;
if _n_=1 and _infile_='Content-type: application/text'
then call symputx('test1','PASS');
else if _n_=2 & _infile_='Content-disposition: attachment; filename=file.txt'
then call symputx('test2','PASS');
run;
%mp_assert(
iftrue=(%str(&test1)=%str(PASS)),
desc=Check first header line
)
%mp_assert(
iftrue=(%str(&test2)=%str(PASS)),
desc=Check second header line
)

View File

@@ -1,29 +0,0 @@
/**
@file
@brief Testing mf_deletefile.sas macro
<h4> SAS Macros </h4>
@li mf_deletefile.sas
@li mf_writefile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let test1file=&sasjswork/myfile1.txt;
%mf_writefile(&test1file,l1=some content)
%mp_assert(
iftrue=(%sysfunc(fileexist(&test1file))=1),
desc=Check &test1file exists
)
%mp_assertscope(SNAPSHOT)
%mf_deletefile(&test1file)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(%sysfunc(fileexist(&test1file))=0),
desc=Check &test1file no longer exists
)

View File

@@ -1,54 +0,0 @@
/**
@file
@brief Testing mf_getuniquelibref macro
@details To test performance you can also use the following macro:
<h4> SAS Macros </h4>
@li mf_getuniquelibref.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* check valid libs */
%mp_assertscope(SNAPSHOT)
%let libshort=%mf_getuniquelibref(prefix=lib);
%mp_assertscope(COMPARE,ignorelist=LIBSHORT)
libname &libshort (work);
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for valid libref &libshort,
outds=work.test_results
)
%let lib7=%mf_getuniquelibref(prefix=libref7);
libname &lib7 (work);
%mp_assert(
iftrue=(&syscc=0),
desc=Checking for valid libref &lib7,
outds=work.test_results
)
/* check for invalid libs */
%let lib8=%mf_getuniquelibref(prefix=lib8char);
%mp_assert(
iftrue=(&lib8=0),
desc=Invalid prefix (8 chars),
outds=work.test_results
)
%let liblong=%mf_getuniquelibref(prefix=invalidlib);
%mp_assert(
iftrue=(&liblong=0),
desc=Checking for invalid libref (long),
outds=work.test_results
)
%let badlib=%mf_getuniquelibref(prefix=8adlib);
%mp_assert(
iftrue=(&badlib=0),
desc=Checking for invalid libref (8adlib),
outds=work.test_results
)

View File

@@ -3,7 +3,6 @@
@brief Testing mp_cntlout.sas macro @brief Testing mp_cntlout.sas macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas @li mp_assertscope.sas

View File

@@ -47,18 +47,4 @@ run;
iftrue=(%mf_nobs(work.mytable3)=2), iftrue=(%mf_nobs(work.mytable3)=2),
desc=Top level returned, desc=Top level returned,
outds=work.test_results outds=work.test_results
) )
%mp_dirlist(path=&root/b, outds=work.myTable4)
%mp_assert(
iftrue=(%mf_nobs(work.mytable4)=0),
desc=Empty table for empty directory,
outds=work.test_results
)
%mp_dirlist(path=&root/notexisting, outds=work.myTable5)
%mp_assert(
iftrue=(%mf_nobs(work.mytable5)=0),
desc=Empty table for non-existing directory,
outds=work.test_results
)

View File

@@ -8,13 +8,6 @@
**/ **/
%macro gsubtest();
%if "%substr(&sysver,1,4)"="V.04" %then %do;
%put %str(ERR)OR: Viya 4 does not support the IO library in lua;
%return;
%end;
/** /**
* test 1 - simple replace * test 1 - simple replace
*/ */
@@ -70,8 +63,4 @@ run;
iftrue=("&strcheck2b"="&str2"), iftrue=("&strcheck2b"="&str2"),
desc=Check that multi line replacement was successful (line3), desc=Check that multi line replacement was successful (line3),
outds=work.test_results outds=work.test_results
) )
%mend gsubtest;
%gsubtest()

View File

@@ -1,61 +0,0 @@
/**
@file
@brief Testing mp_hashdataset.sas macro
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_hashdataset.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* test 1 - regular DS */
data work.test;
set sashelp.vextfl;
missval=.;
misscval='';
run;
%mp_assertscope(SNAPSHOT)
%mp_hashdataset(test)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(&syscc=0),
desc=Regular test works,
outds=work.test_results
)
%mp_hashdataset(test,outds=work.test2)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with output runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test2)=1),
desc=output has 1 row,
outds=work.test_results
)
data work.test3a;
set work.test;
stop;
run;
%mp_hashdataset(test3a,outds=work.test3b)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with zero-row input runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test3b)=1),
desc=test 3 output has 1 row,
outds=work.test_results
)

View File

@@ -3,7 +3,6 @@
@brief Testing mp_loadformat.sas macro @brief Testing mp_loadformat.sas macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mp_loadformat.sas @li mp_loadformat.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas @li mp_assertscope.sas
@@ -13,8 +12,6 @@
/* prep format catalog */ /* prep format catalog */
libname perm (work); libname perm (work);
%mddl_dc_difftable(libds=perm.audit)
data work.loadfmts; data work.loadfmts;
length fmtname $32; length fmtname $32;
eexcl='Y'; eexcl='Y';
@@ -52,7 +49,7 @@ run;
%mp_loadformat(perm.testcat %mp_loadformat(perm.testcat
,work.stagedata ,work.stagedata
,loadtarget=YES ,loadtarget=YES
,auditlibds=perm.audit ,auditlibds=0
,locklibds=0 ,locklibds=0
,delete_col=deleteme ,delete_col=deleteme
,outds_add=add_test1 ,outds_add=add_test1
@@ -76,18 +73,4 @@ run;
iftrue=(%mf_nobs(mod_test1)=100), iftrue=(%mf_nobs(mod_test1)=100),
desc=Test 1 - mod obs, desc=Test 1 - mod obs,
outds=work.test_results outds=work.test_results
) )
%mp_assert(
iftrue=(%mf_nobs(perm.audit)=7329),
desc=Test 1 - audit table updated,
outds=work.test_results
)
data work.difftest;
set perm.audit;
where is_diff=1;
run;
%mp_assert(
iftrue=(%mf_nobs(work.difftest)>0),
desc=Test 1 - diffs were found,
outds=work.test_results
)

View File

@@ -1,95 +0,0 @@
/**
@file
@brief Testing mp_replace.sas macro
<h4> SAS Macros </h4>
@li mp_replace.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let test1="&sasjswork/file.txt";
%let str=replace/me;
%let rep=with/this;
data _null_;
file &test1;
put 'blahblah';
put "blahblah&str.blah";
put 'blahblahblah';
run;
%mp_assertscope(SNAPSHOT)
%mp_replace(&test1, findvar=str, replacevar=rep)
%mp_assertscope(COMPARE)
data _null_;
infile &test1;
input;
if _n_=2 then call symputx('test1result',_infile_);
run;
%mp_assert(
iftrue=("&test1result" = "blahblah&rep.blah"),
desc=Checking first replace,
outds=work.test_results
)
%let test2="&sasjswork/file2.txt";
%let str=%str(replacewith trailing spaces );
%let rep=%str( with more spaces );
data _null_;
file &test2;
put 'blahblah';
put "blahblah&str.blah&str. replace &str.X";
put "blahbreplacewith&str.spacesahblah";
run;
%mp_replace(&test2, findvar=str, replacevar=rep)
data _null_;
infile &test2;
input;
if _n_=2 then call symputx('test2resulta',_infile_);
if _n_=3 then call symputx('test2resultb',_infile_);
run;
%mp_assert(
iftrue=("&test2resulta" = "blahblah&rep.blah&rep. replace &rep.X"),
desc=Checking second replace 2nd row,
outds=work.test_results
)
%mp_assert(
iftrue=("&test2resultb" = "blahbreplacewith&rep.spacesahblah"),
desc=Checking second replace 3rd row,
outds=work.test_results
)
%let test3="&sasjswork/file3.txt";
%let str=%str(replace.string.with.dots );
%let rep=%str( more.dots);
data _null_;
file &test3;
put 'blahblah';
put "blahblah&str.blah&str. replace &str.X";
put "blahbreplacewith&str.spacesahblah";
run;
%mp_replace(&test3, findvar=str, replacevar=rep)
data _null_;
infile &test3;
input;
if _n_=2 then call symputx('test3resulta',_infile_);
if _n_=3 then call symputx('test3resultb',_infile_);
run;
%mp_assert(
iftrue=("&test3resulta" = "blahblah&rep.blah&rep. replace &rep.X"),
desc=Checking third replace 2nd row (dots),
outds=work.test_results
)
%mp_assert(
iftrue=("&test3resultb" = "blahbreplacewith&rep.spacesahblah"),
desc=Checking third replace 3rd row (dots),
outds=work.test_results
)

View File

@@ -1,41 +0,0 @@
/**
@file
@brief Testing mm_webout macro
<h4> SAS Macros </h4>
@li mm_spkexport.sas
@li mp_assert.sas
@li mp_as
**/
%* create sample text file as input to the macro;
filename tmp temp;
data _null_;
file tmp;
put '%let mmxuser="sasdemo";';
put '%let mmxpass="Mars321";';
run;
filename myref "%sysfunc(pathname(work))/mmxexport.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mp_assertscope(SNAPSHOT)
%mm_spkexport(metaloc=%str(/Shared Data)
,outref=myref
,secureref=tmp
,cmdoutloc=%str(/tmp)
)
%mp_assertscope(COMPARE)
data _null_;
infile tmp;
input;
putlog _infile_;
call symputx('nobs',_n_);
run;
%mp_assert(
iftrue=(&nobs>2),
desc=Check if content was created
)

View File

@@ -5,16 +5,12 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mfs_httpheader.sas @li mfs_httpheader.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
**/ **/
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt; %let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt;
%mp_assertscope(SNAPSHOT)
%mfs_httpheader(Content-type,application/csv) %mfs_httpheader(Content-type,application/csv)
%mp_assertscope(COMPARE)
data _null_; data _null_;
infile "&sasjs_stpsrv_header_loc"; infile "&sasjs_stpsrv_header_loc";
input; input;

View File

@@ -1,30 +0,0 @@
/**
@file
@brief Testing ms_createfile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
options mprint;
%let fname=%mf_getuniquename();
%mp_assertscope(SNAPSHOT)
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%mp_assertscope(COMPARE)

View File

@@ -1,61 +0,0 @@
/**
@file
@brief Testing ms_deletefile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li ms_deletefile.sas
@li ms_getfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* first make a remote file */
filename stpcode temp;
%let fname=%mf_getuniquename();
data _null_;
file stpcode;
put "data &fname;run;";
run;
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref)
%let test1=0;
data _null_;
infile testref;
input;
call symputx('test1',_infile_);
run;
%mp_assert(
iftrue=("&test1"="data &fname;run;"),
desc=Make sure the file was created,
outds=work.test_results
)
%mp_assertscope(SNAPSHOT)
%ms_deletefile(/sasjs/tests/&fname..sas,mdebug=1)
%mp_assertscope(COMPARE)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref2)
%let test2=0;
data _null_;
infile testref2;
input;
call symputx('test2',_infile_);
run;
%mp_assert(
iftrue=("&test2"="%str(Err)or: File does not exist."),
desc=Make sure the file was deleted,
outds=work.test_results
)

View File

@@ -1,45 +0,0 @@
/**
@file
@brief Testing ms_getfile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li ms_getfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* first make a remote file */
filename stpcode temp;
%let fname=%mf_getuniquename();
data _null_;
file stpcode;
put "data &fname;run;";
run;
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%mp_assertscope(SNAPSHOT)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref)
%mp_assertscope(COMPARE)
%let test1=0;
data _null_;
infile testref;
input;
call symputx('test1',_infile_);
run;
%mp_assert(
iftrue=("&test1"="data &fname;run;"),
desc=Checking file was created with the same content,
outds=work.test_results
)

View File

@@ -1,44 +0,0 @@
/**
@file
@brief Testing ms_runstp.sas macro
<h4> SAS Macros </h4>
@li ms_runstp.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%mp_assertscope(SNAPSHOT)
%ms_runstp(/Public/app/frs/allan/services/common/appinit
,debug=131
,outref=weboot
)
%mp_assertscope(COMPARE)
libname webeen json (weboot);
data _null_;
infile weboot;
input;
putlog _infile_;
run;
data work.httpheaders;
set webeen.httpheaders;
call symputx('test1',content_type);
run;
data work.log;
set webeen.log;
put (_all_)(=);
if _n_>10 then stop;
run;
%mp_assert(
iftrue=("&test1"="application/json"),
desc=Checking line was created,
outds=work.test_results
)

View File

@@ -1,52 +0,0 @@
/**
@file
@brief Testing mv_deleteviyafolder macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfolder.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mv_createfolder.sas
@li mv_deleteviyafolder.sas
**/
options mprint sgen;
%let folder=%mf_uid();
%let tgtfolder=&mcTestAppLoc/temp/&folder;
/* create a folder */
%mv_createfolder(path=&tgtfolder)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=1),
desc=Check if created folder exists
)
%mp_assertscope(SNAPSHOT)
%mv_deleteviyafolder(path=&tgtfolder)
/* ignore proc json vars */
%mp_assertscope(COMPARE
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADP2LEN MCLIB0_JADVLEN MCLIB2_JADP1LEN
MCLIB2_JADVLEN
)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=0),
desc=Check if deleted folder is gone
)
/* delete folder with content */
%mv_createfolder(path=&tgtfolder/content/and/stuff)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder/content/and/stuff)=1),
desc=Check if folder with content exists
)
%mv_deleteviyafolder(path=&tgtfolder)
%mp_assert(
iftrue=(%mfv_existfolder(&tgtfolder)=0),
desc=Check if deleted folder with subfolders is gone
)

View File

@@ -4,7 +4,6 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createjob.sas @li mv_createjob.sas
@li mv_getjobcode.sas @li mv_getjobcode.sas
@@ -28,17 +27,11 @@ run;
) )
/* now get the code back */ /* now get the code back */
%mp_assertscope(SNAPSHOT)
%mv_getjobcode( %mv_getjobcode(
path=&mcTestAppLoc/services/temp, path=&mcTestAppLoc/services/temp,
name=some_job, name=some_job,
outref=mycode outref=mycode
) )
/* exclude automatic proc json macro variables from scope check */
%mp_assertscope(COMPARE,
ignorelist=MCLIB2_JADP1LEN MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
MCLIB2_JADP3LEN
)
%let diditexist=NO; %let diditexist=NO;
data work.test1; data work.test1;
@@ -53,4 +46,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(&diditexist=NO), iftrue=(&diditexist=NO),
desc=Check if the code that was sent was successfully retrieved desc=Check if the code that was sent was successfully retrieved
) )

View File

@@ -4,7 +4,6 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_assert.sas @li mp_assert.sas
@li mp_assertscope.sas
@li mv_createjob.sas @li mv_createjob.sas
@li mv_jobexecute.sas @li mv_jobexecute.sas
@li mv_jobwaitfor.sas @li mv_jobwaitfor.sas
@@ -50,12 +49,8 @@ data _null_;
run; run;
%* Finally, fetch the log; %* Finally, fetch the log;
%mp_assertscope(SNAPSHOT) %mv_getjoblog(uri=%str(&uri),outref=mylog)
%mv_getjoblog(uri=%str(&uri),outref=mylog,mdebug=1)
/* ignore auto proc json vars */
%mp_assertscope(COMPARE
,ignorelist=MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
)
data _null_; data _null_;
infile mylog end=eof; infile mylog end=eof;
@@ -72,4 +67,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(%str(&found)=1), iftrue=(%str(&found)=1),
desc=Check if the log was still fetched even though endsas was submitted desc=Check if the log was still fetched even though endsas was submitted
) )

View File

@@ -1,33 +1,15 @@
/** /**
@file @file
@brief Testing mv_webout macro @brief Testing mm_webout macro
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mv_webout.sas @li mv_webout.sas
@li mp_assert.sas @li mp_assert.sas
@li mp_assertdsobs.sas
**/ **/
/* testing FETCHing (WEB approach) */
data _null_;
call symputx('sasjs1data','area:$char4.'!!'0d0a'x!!'Adak');
call symputx('sasjs_tables','areas');
run;
%put &=sasjs1data;
%mv_webout(FETCH)
%mp_assertdsobs(work.areas,
desc=Test input table has 1 row,
test=EQUALS 1,
outds=work.test_results
)
%let fref=%mf_getuniquefileref(); %let fref=%mf_getuniquefileref();
%global _metaperson; %global _metaperson;
data some datasets; data some datasets;
@@ -56,4 +38,4 @@ run;
%mp_assert( %mp_assert(
iftrue=(%str(&checkval)=%str(&sysvlong)), iftrue=(%str(&checkval)=%str(&sysvlong)),
desc=Check if the sysvlong value was created desc=Check if the sysvlong value was created
) )

View File

@@ -380,15 +380,8 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; '; put ' )))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -461,7 +454,7 @@ data _null_;
put ' sasjs_tables SYS_JES_JOB_URI; '; put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; '; put '%if %index("&_debug",log) %then %let _debug=131; ';
put ' '; put ' ';
put '%local i tempds table; '; put '%local i tempds; ';
put '%let action=%upcase(&action); '; put '%let action=%upcase(&action); ';
put ' '; put ' ';
put '%if &action=FETCH %then %do; '; put '%if &action=FETCH %then %do; ';
@@ -476,35 +469,60 @@ data _null_;
put ' %end; '; put ' %end; ';
put ' '; put ' ';
put ' /* if the sasjs_tables param is passed, we expect param based upload */ '; put ' /* if the sasjs_tables param is passed, we expect param based upload */ ';
put ' %if %length(&sasjs_tables.X)>1 %then %do; '; put ' %if %length(&sasjs_tables.XX)>2 %then %do; ';
put ' filename _sasjs "%sysfunc(pathname(work))/sasjs.lua"; ';
put ' data _null_; ';
put ' file _sasjs; ';
put ' put ''s=sas.symget("sasjs_tables")''; ';
put ' put ''if(s:sub(1,7) == "%nrstr(")''; ';
put ' put ''then''; ';
put ' put '' tablist=s:sub(8,s:len()-1)''; ';
put ' put ''else''; ';
put ' put '' tablist=s''; ';
put ' put ''end''; ';
put ' put ''for i = 1,sas.countw(tablist) ''; ';
put ' put ''do ''; ';
put ' put '' tab=sas.scan(tablist,i)''; ';
put ' put '' sasdata=""''; ';
put ' put '' if (sas.symexist("sasjs"..i.."data0")==0)''; ';
put ' put '' then''; ';
put ' /* TODO - condense this logic */ ';
put ' put '' s=sas.symget("sasjs"..i.."data")''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=s''; ';
put ' put '' end''; ';
put ' put '' else''; ';
put ' put '' for d = 1, sas.symget("sasjs"..i.."data0")''; ';
put ' put '' do''; ';
put ' put '' s=sas.symget("sasjs"..i.."data"..d)''; ';
put ' put '' if(s:sub(1,7) == "%nrstr(")''; ';
put ' put '' then''; ';
put ' put '' sasdata=sasdata..s:sub(8,s:len()-1)''; ';
put ' put '' else''; ';
put ' put '' sasdata=sasdata..s''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' end''; ';
put ' put '' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")''; ';
put ' put '' io.output(file)''; ';
put ' put '' io.write(sasdata)''; ';
put ' put '' io.close(file)''; ';
put ' put ''end''; ';
put ' run; ';
put ' %inc _sasjs; ';
put ' '; put ' ';
put ' /* convert data from macro variables to datasets */ '; put ' /* now read in the data */ ';
put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); '; put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); ';
put ' %let table=%scan(&sasjs_tables,&i,%str( )); '; put ' %local table; %let table=%scan(&sasjs_tables,&i); ';
put ' %if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1; ';
put ' data _null_; ';
put ' file "%sysfunc(pathname(work))/&table..csv" recfm=n; ';
put ' retain nrflg 0; ';
put ' length line $32767; ';
put ' do i=1 to &&sasjs&i.data0; ';
put ' if &&sasjs&i.data0=1 then line=symget("sasjs&i.data"); ';
put ' else line=symget(cats("sasjs&i.data",i)); ';
put ' if i=1 and substr(line,1,7)=''%nrstr('' then do; ';
put ' nrflg=1; ';
put ' line=substr(line,8); ';
put ' end; ';
put ' if i=&&sasjs&i.data0 and nrflg=1 then do; ';
put ' line=substr(line,1,length(line)-1); ';
put ' end; ';
put ' put line +(-1) @; ';
put ' end; ';
put ' run; ';
put ' data _null_; '; put ' data _null_; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; '; put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; ';
put ' input; '; put ' input; ';
put ' if _n_=1 then call symputx(''input_statement'',_infile_); '; put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' list; '; put ' list; ';
put ' data work.&table; '; put ' data &table; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd '; put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
put ' termstr=crlf; '; put ' termstr=crlf; ';
put ' input &input_statement; '; put ' input &input_statement; ';
@@ -637,8 +655,7 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; '; put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; '; put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
put ' /* sometimes SAS will add @domain extension - remove for consistency */ '; put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
put ' /* but be sure to quote in case of usernames with commas */ '; put ' %else %let user=%scan(&&&metavar,1,@); ';
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %end; '; put ' %end; ';
put ' %else %let user=&sysuserid; '; put ' %else %let user=&sysuserid; ';
put ' '; put ' ';

View File

@@ -8,16 +8,10 @@
%mv_deleteviyafolder(path=/Public/test) %mv_deleteviyafolder(path=/Public/test)
@param [in] path= The full path of the folder to be deleted @param path= The full path of the folder to be deleted
@param [in] access_token_var= (ACCESS_TOKEN) The global macro variable to @param access_token_var= The global macro variable to contain the access token
contain the access token @param grant_type= valid values are "password" or "authorization_code" (unquoted).
@param [in] grant_type= (sas_services) Valid values are: The default is authorization_code.
@li password
@li authorization_code
@li detect - will check if access_token exists, if not will use sas_services
if a SASStudioV session else authorization_code. Default option.
@li sas_services - will use oauth_bearer=sas_services.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.04 @version VIYA V.03.04
@@ -25,7 +19,6 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@li mf_existds.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas
@@ -36,7 +29,6 @@
%macro mv_deleteviyafolder(path= %macro mv_deleteviyafolder(path=
,access_token_var=ACCESS_TOKEN ,access_token_var=ACCESS_TOKEN
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0
); );
%local oauth_bearer; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
@@ -113,17 +105,14 @@ run;
%let libref1a=%mf_getuniquelibref(); %let libref1a=%mf_getuniquelibref();
libname &libref1a JSON fileref=&fname1a; libname &libref1a JSON fileref=&fname1a;
%if %mf_existds(&libref1a..items_links) %then %do; data _null_;
data _null_; set &libref1a..items_links;
set &libref1a..items_links; if href=:'/folders/folders' then return;
if href=:'/folders/folders' then return; if rel='deleteResource' then
if rel='deleteResource' then call execute('proc http method="DELETE" url='!!quote("&base_uri"!!trim(href))
call execute('proc http method="DELETE" url=' !!'; headers "Authorization"="Bearer &&&access_token_var" '
!!quote("&base_uri"!!trim(href)) !!' "Accept"="*/*";run; /**/');
!!'; headers "Authorization"="Bearer &&&access_token_var" ' run;
!!' "Accept"="*/*";run; /**/');
run;
%end;
%put &sysmacroname: perform the delete operation ; %put &sysmacroname: perform the delete operation ;
%local fname2; %local fname2;
@@ -144,11 +133,9 @@ run;
%end; %end;
%else %put &sysmacroname: &path successfully deleted; %else %put &sysmacroname: &path successfully deleted;
%if &mdebug=0 %then %do; /* clear refs */
/* clear refs */ filename &fname1 clear;
filename &fname1 clear; filename &fname2 clear;
filename &fname2 clear; libname &libref1 clear;
libname &libref1 clear;
%end;
%mend mv_deleteviyafolder; %mend mv_deleteviyafolder;

View File

@@ -32,7 +32,7 @@
,grant_type=sas_services ,grant_type=sas_services
,outds=work.viyagroups ,outds=work.viyagroups
); );
%local oauth_bearer base_uri fname1 libref1; %local oauth_bearer;
%if &grant_type=detect %then %do; %if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code; %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services; %else %let grant_type=sas_services;
@@ -50,10 +50,11 @@
) )
options noquotelenmax; options noquotelenmax;
/* location of rest apis */ %local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* fetching folder details for provided path */ /* fetching folder details for provided path */
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let libref1=%mf_getuniquelibref(); %let libref1=%mf_getuniquelibref();
@@ -77,8 +78,9 @@ data &outds;
run; run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
libname &libref1 clear; libname &libref1 clear;
%mend mv_getgroups; %mend mv_getgroups;

View File

@@ -33,6 +33,7 @@
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mv_getfoldermembers.sas @li mv_getfoldermembers.sas
@li ml_json.sas
**/ **/
@@ -43,9 +44,9 @@
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg bufsize varcnt fname1 fname2 errmsg; %local dbg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname local entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
%end; %end;
%else %let dbg=*; %else %let dbg=*;
@@ -103,6 +104,7 @@ run;
) )
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&joburi"; url="&base_uri&joburi";
@@ -112,95 +114,37 @@ proc http method='GET' out=&fname1 &oauth_bearer
%end; %end;
; ;
run; run;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%if &mdebug=1 %then %do; %do;
data _null_; data _null_;infile &fname1;input;putlog _infile_;run;
infile &fname1; %mp_abort(mac=&sysmacroname
input; ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
putlog _infile_; )
run;
%end; %end;
%local fname2 fname3 fpath1 fpath2 fpath3;
%mp_abort(
iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%let fname2=%mf_getuniquefileref(); %let fname2=%mf_getuniquefileref();
filename &fname2 temp ; %let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
/* cannot use lua IO package as not available in Viya 4 */ /* compile the lua JSON module */
/* so use data step to read the JSON until the string `"code":"` is found */ %ml_json()
/* read using LUA - this allows the code to be of any length */
data _null_; data _null_;
file &fname2 recfm=n; file "&fpath3..lua";
infile &fname1 lrecl=1 recfm=n; put '
input sourcechar $char1. @@; infile = io.open (sas.symget("fpath1"), "r")
format sourcechar hex2.; outfile = io.open (sas.symget("fpath2"), "w")
retain startwrite 0; io.input(infile)
if startwrite=0 and sourcechar='"' then do; local resp=json.decode(io.read())
reentry: local job=resp["code"]
input sourcechar $ 1. @@; outfile:write(job)
if sourcechar='c' then do; io.close(infile)
reentry2: io.close(outfile)
input sourcechar $ 1. @@; ';
if sourcechar='o' then do;
input sourcechar $ 1. @@;
if sourcechar='d' then do;
input sourcechar $ 1. @@;
if sourcechar='e' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
input sourcechar $ 1. @@;
if sourcechar=':' then do;
input sourcechar $ 1. @@;
if sourcechar='"' then do;
putlog 'code found';
startwrite=1;
input sourcechar $ 1. @@;
end;
end;
else if sourcechar='c' then goto reentry2;
end;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
else if sourcechar='"' then goto reentry;
end;
/* once the `"code":"` string is found, write until unescaped `"` is found */
if startwrite=1 then do;
if sourcechar='\' then do;
input sourcechar $ 1. @@;
if sourcechar in ('"','\') then put sourcechar char1.;
else if sourcechar='n' then put '0A'x;
else if sourcechar='r' then put '0D'x;
else if sourcechar='t' then put '09'x;
else if sourcechar='u' then do;
length uni $4;
input uni $ 4. @@;
sourcechar=unicode('\u'!!uni);
put sourcechar char1.;
end;
else do;
call symputx('errmsg',"Uncaught escape char: "!!sourcechar,'l');
call symputx('syscc',99);
stop;
end;
end;
else if sourcechar='"' then stop;
else put sourcechar char1.;
end;
run; run;
%inc "&fpath3..lua";
%mp_abort(iftrue=("&syscc"="99")
,mac=mv_getjobcode
,msg=%str(&errmsg)
)
/* export to desired destination */ /* export to desired destination */
%if "&outref"="0" %then %do; %if "&outref"="0" %then %do;
data _null_; data _null_;
@@ -225,6 +169,7 @@ run;
/* clear refs */ /* clear refs */
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
filename &fname3 clear;
%end; %end;
%mend mv_getjobcode; %mend mv_getjobcode;

View File

@@ -86,8 +86,7 @@
@li mp_abort.sas @li mp_abort.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_existfileref.sas @li mf_existfileref.sas
@li mf_getuniquefileref.sas @li ml_json.sas
@li mf_getuniquelibref.sas
**/ **/
@@ -96,7 +95,7 @@
,grant_type=sas_services ,grant_type=sas_services
,mdebug=0 ,mdebug=0
); );
%local dbg libref1 libref2 loglocation fname1 fname2; %local dbg;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname entry vars:; %put &sysmacroname entry vars:;
%put _local_; %put _local_;
@@ -155,8 +154,8 @@ options noquotelenmax;
%let base_uri=%mf_getplatform(VIYARESTAPI); %let base_uri=%mf_getplatform(VIYARESTAPI);
/* prepare request*/ /* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&uri"; url="&base_uri&uri";
headers headers
@@ -176,19 +175,37 @@ run;
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
%local fname2 fname3 fpath1 fpath2 fpath3;
%let fname2=%mf_getuniquefileref();
%let fname3=%mf_getuniquefileref();
%let fpath1=%sysfunc(pathname(&fname1));
%let fpath2=%sysfunc(pathname(&fname2));
%let fpath3=%sysfunc(pathname(&fname3));
%let libref1=%mf_getuniquelibref(); /* compile the lua JSON module */
libname &libref1 JSON fileref=&fname1; %ml_json()
/* read using LUA - this allows the code to be of any length */
data _null_; data _null_;
set &libref1..root; file "&fpath3..lua";
call symputx('loglocation',loglocation,'l'); put '
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
local logloc=resp["logLocation"]
outfile:write(logloc)
io.close(infile)
io.close(outfile)
';
run; run;
%inc "&fpath3..lua";
/* validate log path*/ /* get log path*/
%let errflg=1; %let errflg=1;
%let errmsg=No loglocation entry in &fname1 fileref; %let errmsg=No entry in &fname2 fileref;
data _null_; data _null_;
uri=symget('loglocation'); infile &fname2;
input;
uri=cats(_infile_);
if length(uri)<12 then do; if length(uri)<12 then do;
call symputx('errflg',1); call symputx('errflg',1);
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l'); call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
@@ -215,7 +232,7 @@ run;
/* we have a log uri - now fetch the log */ /* we have a log uri - now fetch the log */
%&dbg.put &sysmacroname: querying &base_uri&logloc/content; %&dbg.put &sysmacroname: querying &base_uri&logloc/content;
proc http method='GET' out=&fname2 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&logloc/content?limit=10000"; url="&base_uri&logloc/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -226,14 +243,14 @@ run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/content; %put &sysmacroname: fetching log content from &base_uri&logloc/content;
data _null_;infile &fname2;input;putlog _infile_;run; data _null_;infile &fname1;input;putlog _infile_;run;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE=400 %then %do; %if &SYS_PROCHTTP_STATUS_CODE=400 %then %do;
/* fetch log from parent session */ /* fetch log from parent session */
%let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1); %let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1);
%&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content; %&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content;
proc http method='GET' out=&fname2 &oauth_bearer proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&logloc/log/content?limit=10000"; url="&base_uri&logloc/log/content?limit=10000";
headers headers
%if &grant_type=authorization_code %then %do; %if &grant_type=authorization_code %then %do;
@@ -243,32 +260,47 @@ run;
run; run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
%put &sysmacroname: fetching log content from &base_uri&logloc/log/content; %put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
data _null_;infile &fname2;input;putlog _infile_;run; data _null_;infile &fname1;input;putlog _infile_;run;
%end; %end;
%end; %end;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
%then %do; %then %do;
%if &mdebug ne 1 %then %do; /* have already output above */ %if &mdebug ne 1 %then %do; /* have already output above */
data _null_;infile &fname2;input;putlog _infile_;run; data _null_;infile &fname1;input;putlog _infile_;run;
%end; %end;
%mp_abort(mac=&sysmacroname %mp_abort(mac=&sysmacroname
,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE) ,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
) )
%end; %end;
%let libref2=%mf_getuniquelibref();
libname &libref2 JSON fileref=&fname2;
data _null_; data _null_;
file "&fpath3..lua";
put '
infile = io.open (sas.symget("fpath1"), "r")
outfile = io.open (sas.symget("fpath2"), "w")
io.input(infile)
local resp=json.decode(io.read())
for i, v in pairs(resp["items"]) do
outfile:write(v.line,"\n")
end
io.close(infile)
io.close(outfile)
';
run;
%inc "&fpath3..lua";
/* write log out to the specified fileref */
data _null_;
infile &fname2 end=last;
file &outref mod; file &outref mod;
if _n_=1 then do; if _n_=1 then do;
put "/** SASJS Viya Job Log Extract start: &uri **/"; put "/** SASJS Viya Job Log Extract start: &uri **/";
end; end;
set &libref2..items end=last; input;
put _infile_;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
putlog line; putlog _infile_;
%end; %end;
put line;
if last then do; if last then do;
put "/** SASJS Viya Job Log Extract end: &uri **/"; put "/** SASJS Viya Job Log Extract end: &uri **/";
end; end;
@@ -277,8 +309,7 @@ run;
%if &mdebug=0 %then %do; %if &mdebug=0 %then %do;
filename &fname1 clear; filename &fname1 clear;
filename &fname2 clear; filename &fname2 clear;
libname &libref1 clear; filename &fname3 clear;
libname &libref2 clear;
%end; %end;
%else %do; %else %do;
%put &sysmacroname exit vars:; %put &sysmacroname exit vars:;

View File

@@ -81,7 +81,6 @@
@li mf_loc.sas @li mf_loc.sas
@li mf_getquotedstr.sas @li mf_getquotedstr.sas
@li mf_getuser.sas @li mf_getuser.sas
@li mp_abort.sas
**/ **/
@@ -99,7 +98,7 @@
,refresh_token_validity=DEFAULT ,refresh_token_validity=DEFAULT
,outjson=_null_ ,outjson=_null_
); );
%local fname1 fname2 fname3 libref access_token url tokloc msg; %local fname1 fname2 fname3 libref access_token url tokloc;
%if client_name=DEFAULT %then %let client_name= %if client_name=DEFAULT %then %let client_name=
Generated by %mf_getuser() (&sysuserid) on %sysfunc(datetime(),datetime19. Generated by %mf_getuser() (&sysuserid) on %sysfunc(datetime(),datetime19.
@@ -113,11 +112,10 @@ options noquotelenmax;
%let tokloc=%mf_loc(VIYACONFIG)&tokloc/client.token; %let tokloc=%mf_loc(VIYACONFIG)&tokloc/client.token;
%if %sysfunc(fileexist(&tokloc))=0 %then %do; %if %sysfunc(fileexist(&tokloc))=0 %then %do;
%let msg=Unable to access the consul token at &tokloc; %put &sysmacroname: unable to access the consul token at &tokloc;
%put &sysmacroname: &msg;
%put Try passing the value in the consul= macro parameter; %put Try passing the value in the consul= macro parameter;
%put See docs: https://core.sasjs.io/mv__registerclient_8sas.html; %put See docs: https://core.sasjs.io/mv__registerclient_8sas.html;
%mp_abort(mac=mv_registerclient,msg=%str(&msg)) %abort;
%end; %end;
data _null_; data _null_;

View File

@@ -49,7 +49,7 @@
sasjs_tables SYS_JES_JOB_URI; sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131; %if %index("&_debug",log) %then %let _debug=131;
%local i tempds table; %local i tempds;
%let action=%upcase(&action); %let action=%upcase(&action);
%if &action=FETCH %then %do; %if &action=FETCH %then %do;
@@ -64,35 +64,60 @@
%end; %end;
/* if the sasjs_tables param is passed, we expect param based upload */ /* if the sasjs_tables param is passed, we expect param based upload */
%if %length(&sasjs_tables.X)>1 %then %do; %if %length(&sasjs_tables.XX)>2 %then %do;
filename _sasjs "%sysfunc(pathname(work))/sasjs.lua";
data _null_;
file _sasjs;
put 's=sas.symget("sasjs_tables")';
put 'if(s:sub(1,7) == "%nrstr(")';
put 'then';
put ' tablist=s:sub(8,s:len()-1)';
put 'else';
put ' tablist=s';
put 'end';
put 'for i = 1,sas.countw(tablist) ';
put 'do ';
put ' tab=sas.scan(tablist,i)';
put ' sasdata=""';
put ' if (sas.symexist("sasjs"..i.."data0")==0)';
put ' then';
/* TODO - condense this logic */
put ' s=sas.symget("sasjs"..i.."data")';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=s';
put ' end';
put ' else';
put ' for d = 1, sas.symget("sasjs"..i.."data0")';
put ' do';
put ' s=sas.symget("sasjs"..i.."data"..d)';
put ' if(s:sub(1,7) == "%nrstr(")';
put ' then';
put ' sasdata=sasdata..s:sub(8,s:len()-1)';
put ' else';
put ' sasdata=sasdata..s';
put ' end';
put ' end';
put ' end';
put ' file = io.open(sas.pathname("work").."/"..tab..".csv", "a")';
put ' io.output(file)';
put ' io.write(sasdata)';
put ' io.close(file)';
put 'end';
run;
%inc _sasjs;
/* convert data from macro variables to datasets */ /* now read in the data */
%do i=1 %to %sysfunc(countw(&sasjs_tables)); %do i=1 %to %sysfunc(countw(&sasjs_tables));
%let table=%scan(&sasjs_tables,&i,%str( )); %local table; %let table=%scan(&sasjs_tables,&i);
%if %symexist(sasjs&i.data0)=0 %then %let sasjs&i.data0=1;
data _null_;
file "%sysfunc(pathname(work))/&table..csv" recfm=n;
retain nrflg 0;
length line $32767;
do i=1 to &&sasjs&i.data0;
if &&sasjs&i.data0=1 then line=symget("sasjs&i.data");
else line=symget(cats("sasjs&i.data",i));
if i=1 and substr(line,1,7)='%nrstr(' then do;
nrflg=1;
line=substr(line,8);
end;
if i=&&sasjs&i.data0 and nrflg=1 then do;
line=substr(line,1,length(line)-1);
end;
put line +(-1) @;
end;
run;
data _null_; data _null_;
infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
input; input;
if _n_=1 then call symputx('input_statement',_infile_); if _n_=1 then call symputx('input_statement',_infile_);
list; list;
data work.&table; data &table;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
termstr=crlf; termstr=crlf;
input &input_statement; input &input_statement;