1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-15 16:14:36 +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 2407 deletions

View File

@@ -117,15 +117,6 @@
"contributions": [
"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,

View File

@@ -1,12 +1,5 @@
#!/bin/bash
# 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
sasjs lint
# Avoid commits to the master branch
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:
- init: npm install -g npm
- command: npm i
- command: npm i -g @sasjs/cli
- init: |
nvm install --lts
npm i -g @sasjs/cli
image:
file: .gitpod.dockerfile
@@ -24,4 +24,4 @@ github:
# add a "Review in Gitpod" button to pull requests (defaults to false)
addBadge: 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).
### FCMP library (All Platforms)
#### FCMP library (All Platforms)
- Function and macro names are identical, except for special cases
- 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:
* 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)
* `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.
@@ -217,19 +216,11 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
![](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 ✨
<!-- 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 -->
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/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>
</tr>
</table>

1321
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);
@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)
<h4> SAS Macros </h4>
@li mf_getplatform.sas
@version 8
@author Allan Bowe
**/
/** @cond */
%macro mf_existfeature(feature
)/*/STORE SOURCE*/;
%let feature=%upcase(&feature);
@@ -27,11 +29,7 @@
%let platform=%mf_getplatform();
%if &feature= %then %do;
%put No feature was requested for detection;
%end;
%else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0;
%else 1;
%put Supported features: PROCLUA;
%end;
%else %if &feature=PROCLUA %then %do;
/* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */
@@ -45,4 +43,5 @@
%put &sysmacroname: &feature not found;
%end;
%mend mf_existfeature;
/** @endcond */
/** @endcond */

View File

@@ -14,44 +14,27 @@
> mclib3
A blank value is returned if no usable libname is determined.
@param [in] prefix= (mclib) first part of the returned libref. As librefs can
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.
@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 maxtries= the last part of the libref. Provide an integer value.
@version 9.2
@author Allan Bowe
**/
%macro mf_getuniquelibref(prefix=mclib,maxtries=1000);
%local x;
%if ( %length(&prefix) gt 7 ) %then %do;
%put %str(ERR)OR: The prefix parameter cannot exceed 7 characters.;
0
%local x libref;
%let x=0;
%do x=0 %to &maxtries;
%if %sysfunc(libref(&prefix&x)) ne 0 %then %do;
%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;
%end;
%else %if (%sysfunc(NVALID(&prefix,v7))=0) %then %do;
%put %str(ERR)OR: Invalid prefix (&prefix);
0
%return;
%end;
/* 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
%put unable to find available libref in range &prefix.0-&maxtries;
%mend mf_getuniquelibref;

View File

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

View File

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

View File

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

View File

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

View File

@@ -94,13 +94,6 @@ data &out_ds(compress=no
%end;
if rc = 0 then do;
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" */
numopts=doptnum(did);
do i=1 to numopts;
@@ -108,6 +101,12 @@ data &out_ds(compress=no
if foption=:'Directory' then i=numopts;
end;
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);
end;
else do;
@@ -152,7 +151,6 @@ run;
data &out_ds;
set &out_ds;
length infoname infoval $60 fref $8;
if _n_=1 then call missing(fref);
rc=filename(fref,filepath);
drop rc infoname fid i close fref;
if file_or_folder='file' then do;
@@ -244,4 +242,4 @@ run;
proc sql;
drop table &out_ds;
%mend mp_dirlist;
%mend mp_dirlist;

View File

@@ -48,11 +48,6 @@
outfile=0
)/*/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()
%mend mp_gsubfile;

View File

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

View File

@@ -203,15 +203,8 @@
prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1,
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/\\/\\\\/',-1,&&name&i)
))))))))))))!!'"';
)))))!!'"';
%end;
%end;
run;

View File

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

View File

@@ -1,8 +1,7 @@
/**
@file
@brief Mechanism for locking tables to prevent parallel modifications
@details Uses a control table to enable ANY table to be locked for updates
(not just SAS datasets).
@details Uses a control table to enable ANY table to be locked for updates.
Only useful if every update uses the macro! Used heavily within
[Data Controller for SAS](https://datacontroller.io).
@@ -16,7 +15,7 @@
length is 200 characters.
@param [out] ctl_ds= (0) The control table which controls the actual locking.
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] 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.)
%let sep=!!;
%end;
),$hex32.)
),hex32.)
%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)
@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] inref= fileref of file to be sent (if provided, overrides `inloc`)
@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>
@li mp_abort.sas
@param [in] libref The libref (not name) of the metadata library
@param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
@param libref the libref (not name) of the metadata library
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return
@returns libname statement
@@ -28,11 +28,11 @@
libref
,mAbort=HARD
)/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_;
length liburi LibName msg $200;
length liburi LibName $200;
call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do;
@@ -40,30 +40,7 @@
/* now try and assign it */
if libname("&libref",,'meta',cats('liburi="',liburi,'";')) ne 0 then do;
putlog "&libref could not be assigned";
putlog liburi=;
/**
* 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');
call symputx('msg',sysmsg(),'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end;
else do;
@@ -82,16 +59,20 @@
end;
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;
%else %do;
%put NOTE: Library &libref is already assigned;
%end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib;

View File

@@ -236,15 +236,8 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
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/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; ';
put ' )))))!!''"''; ';
put ' %end; ';
put ' %end; ';
put ' run; ';
@@ -460,8 +453,7 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
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=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %else %let user=%scan(&&&metavar,1,@); ';
put ' %end; ';
put ' %else %let user=&sysuserid; ';
put ' ';

View File

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

View File

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

2
package-lock.json generated
View File

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

View File

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

View File

@@ -4,8 +4,11 @@
"base",
"ddl",
"fcmp",
"lua",
"meta",
"metax",
"server",
"viya",
"lua",
"tests/crossplatform",
"tests/ddl"
],
@@ -36,9 +39,14 @@
},
"appLoc": "/Public/temp/macrocore",
"macroFolders": [
"viya",
"tests/viyaonly"
],
"programFolders": [],
"binaryFolders": [],
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
},
"contextName": "SAS Job Execution compute context"
},
{
@@ -50,8 +58,6 @@
},
"appLoc": "/Shared Data/temp/macrocore",
"macroFolders": [
"meta",
"metax",
"tests/sas9only"
],
"programFolders": [],
@@ -65,49 +71,23 @@
},
{
"name": "server",
"serverUrl": "",
"serverUrl": "https://sas.analytium.co.uk:5000",
"serverType": "SASJS",
"httpsAgentOptions": {
"allowInsecureRequests": false
},
"appLoc": "/sasjs/core",
"appLoc": "/Shared Data/temp/macrocore",
"macroFolders": [
"server",
"tests/serveronly"
],
"programFolders": [],
"binaryFolders": [],
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
"deployServicePack": true
}
},
{
"name": "docsonly",
"serverType": "SAS9",
"appLoc": "dummy",
"macroFolders": [
"meta",
"metax",
"server",
"viya",
"tests/sas9only",
"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_;
set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1;
call symputx(cats('wt',i),name,'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
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mp_cntlout.sas
@li mp_assert.sas
@li mp_assertscope.sas

View File

@@ -47,18 +47,4 @@ run;
iftrue=(%mf_nobs(work.mytable3)=2),
desc=Top level returned,
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
*/
@@ -70,8 +63,4 @@ run;
iftrue=("&strcheck2b"="&str2"),
desc=Check that multi line replacement was successful (line3),
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
<h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mp_loadformat.sas
@li mp_assert.sas
@li mp_assertscope.sas
@@ -13,8 +12,6 @@
/* prep format catalog */
libname perm (work);
%mddl_dc_difftable(libds=perm.audit)
data work.loadfmts;
length fmtname $32;
eexcl='Y';
@@ -52,7 +49,7 @@ run;
%mp_loadformat(perm.testcat
,work.stagedata
,loadtarget=YES
,auditlibds=perm.audit
,auditlibds=0
,locklibds=0
,delete_col=deleteme
,outds_add=add_test1
@@ -76,18 +73,4 @@ run;
iftrue=(%mf_nobs(mod_test1)=100),
desc=Test 1 - mod obs,
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>
@li mfs_httpheader.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt;
%mp_assertscope(SNAPSHOT)
%mfs_httpheader(Content-type,application/csv)
%mp_assertscope(COMPARE)
data _null_;
infile "&sasjs_stpsrv_header_loc";
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>
@li mp_assert.sas
@li mp_assertscope.sas
@li mv_createjob.sas
@li mv_getjobcode.sas
@@ -28,17 +27,11 @@ run;
)
/* now get the code back */
%mp_assertscope(SNAPSHOT)
%mv_getjobcode(
path=&mcTestAppLoc/services/temp,
name=some_job,
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;
data work.test1;
@@ -53,4 +46,4 @@ run;
%mp_assert(
iftrue=(&diditexist=NO),
desc=Check if the code that was sent was successfully retrieved
)
)

View File

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

View File

@@ -1,33 +1,15 @@
/**
@file
@brief Testing mv_webout macro
@brief Testing mm_webout macro
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mv_webout.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();
%global _metaperson;
data some datasets;
@@ -56,4 +38,4 @@ run;
%mp_assert(
iftrue=(%str(&checkval)=%str(&sysvlong)),
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/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
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/\\/\\\\/'',-1,&&name&i) ';
put ' ))))))))))))!!''"''; ';
put ' )))))!!''"''; ';
put ' %end; ';
put ' %end; ';
put ' run; ';
@@ -461,7 +454,7 @@ data _null_;
put ' sasjs_tables SYS_JES_JOB_URI; ';
put '%if %index("&_debug",log) %then %let _debug=131; ';
put ' ';
put '%local i tempds table; ';
put '%local i tempds; ';
put '%let action=%upcase(&action); ';
put ' ';
put '%if &action=FETCH %then %do; ';
@@ -476,35 +469,60 @@ data _null_;
put ' %end; ';
put ' ';
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 ' /* convert data from macro variables to datasets */ ';
put ' /* now read in the data */ ';
put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); ';
put ' %let table=%scan(&sasjs_tables,&i,%str( )); ';
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 ' %local table; %let table=%scan(&sasjs_tables,&i); ';
put ' data _null_; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ; ';
put ' input; ';
put ' if _n_=1 then call symputx(''input_statement'',_infile_); ';
put ' list; ';
put ' data work.&table; ';
put ' data &table; ';
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
put ' termstr=crlf; ';
put ' input &input_statement; ';
@@ -637,8 +655,7 @@ data _null_;
put ' %else %if %symexist(&metavar) %then %do; ';
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
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=%unquote(%scan(%quote(&&&metavar),1,@)); ';
put ' %else %let user=%scan(&&&metavar,1,@); ';
put ' %end; ';
put ' %else %let user=&sysuserid; ';
put ' ';

View File

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

View File

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

View File

@@ -33,6 +33,7 @@
@li mf_getplatform.sas
@li mf_getuniquefileref.sas
@li mv_getfoldermembers.sas
@li ml_json.sas
**/
@@ -43,9 +44,9 @@
,grant_type=sas_services
,mdebug=0
);
%local dbg bufsize varcnt fname1 fname2 errmsg;
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname local entry vars:;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
@@ -103,6 +104,7 @@ run;
)
/* prepare request*/
%local fname1;
%let fname1=%mf_getuniquefileref();
proc http method='GET' out=&fname1 &oauth_bearer
url="&base_uri&joburi";
@@ -112,95 +114,37 @@ proc http method='GET' out=&fname1 &oauth_bearer
%end;
;
run;
%if &mdebug=1 %then %do;
data _null_;
infile &fname1;
input;
putlog _infile_;
run;
%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
%do;
data _null_;infile &fname1;input;putlog _infile_;run;
%mp_abort(mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%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)
)
%local fname2 fname3 fpath1 fpath2 fpath3;
%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 */
/* so use data step to read the JSON until the string `"code":"` is found */
/* compile the lua JSON module */
%ml_json()
/* read using LUA - this allows the code to be of any length */
data _null_;
file &fname2 recfm=n;
infile &fname1 lrecl=1 recfm=n;
input sourcechar $char1. @@;
format sourcechar hex2.;
retain startwrite 0;
if startwrite=0 and sourcechar='"' then do;
reentry:
input sourcechar $ 1. @@;
if sourcechar='c' then do;
reentry2:
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;
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())
local job=resp["code"]
outfile:write(job)
io.close(infile)
io.close(outfile)
';
run;
%mp_abort(iftrue=("&syscc"="99")
,mac=mv_getjobcode
,msg=%str(&errmsg)
)
%inc "&fpath3..lua";
/* export to desired destination */
%if "&outref"="0" %then %do;
data _null_;
@@ -225,6 +169,7 @@ run;
/* clear refs */
filename &fname1 clear;
filename &fname2 clear;
filename &fname3 clear;
%end;
%mend mv_getjobcode;

View File

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

View File

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

View File

@@ -49,7 +49,7 @@
sasjs_tables SYS_JES_JOB_URI;
%if %index("&_debug",log) %then %let _debug=131;
%local i tempds table;
%local i tempds;
%let action=%upcase(&action);
%if &action=FETCH %then %do;
@@ -64,35 +64,60 @@
%end;
/* 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));
%let table=%scan(&sasjs_tables,&i,%str( ));
%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;
%local table; %let table=%scan(&sasjs_tables,&i);
data _null_;
infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
input;
if _n_=1 then call symputx('input_statement',_infile_);
list;
data work.&table;
data &table;
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
termstr=crlf;
input &input_statement;