mirror of
https://github.com/sasjs/core.git
synced 2025-12-11 14:34:35 +00:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94e83f6b8d | ||
|
|
35a6dede6f | ||
|
|
039ec397dd | ||
|
|
dce4630eb8 | ||
|
|
1e142f042b | ||
|
|
7caca2f139 | ||
|
|
61556b2de8 | ||
|
|
9e12409389 | ||
|
|
c8050f5a79 | ||
|
|
cb4f71c7cd | ||
|
|
a39f4e4eee | ||
|
|
b525b4171d | ||
|
|
f2d80b3b63 | ||
|
|
96dda87f37 | ||
|
|
3435509eec | ||
|
|
42f2767129 | ||
|
|
099a5f7840 | ||
|
|
c83ea705a2 | ||
|
|
9ea6c875f2 | ||
|
|
0728f72c4f | ||
|
|
a90a6f00cf | ||
|
|
f71e53af8d | ||
|
|
cc1b971e19 | ||
|
|
8484c752ed | ||
|
|
8bd31e6c97 | ||
|
|
f9b0f87f44 | ||
|
|
d7e9f10291 | ||
|
|
3edc3587b3 | ||
|
|
63bf00e28f | ||
|
|
6b2574947a | ||
|
|
eb9027ecb6 | ||
|
|
2ad931a566 | ||
|
|
cebe119304 | ||
|
|
bd3082d7e3 | ||
|
|
11da53f1cb | ||
|
|
c4cb0b2395 | ||
|
|
58614e9a3d | ||
|
|
c94c334c4b | ||
|
|
3bf44405f8 | ||
|
|
db68a256cb | ||
|
|
611fac6338 | ||
|
|
ddd120bb75 | ||
|
|
0d75e0bad8 | ||
|
|
ba8c4ac844 | ||
|
|
6938a42896 | ||
|
|
efff77c94e | ||
|
|
2b10cf6192 | ||
|
|
134b91f266 | ||
|
|
969f551e10 | ||
|
|
26623ba085 | ||
|
|
8eb495890d | ||
|
|
c1a30977f1 | ||
|
|
9a6be61651 | ||
|
|
388839039e | ||
|
|
e760a89a6a | ||
|
|
d2e30267e8 | ||
|
|
190dbddfe3 | ||
|
|
05e769794e | ||
|
|
558ebaf6f2 | ||
|
|
970b56fe5a | ||
|
|
c2597bd07b | ||
|
|
c4baca477b | ||
|
|
7726b0e0b0 | ||
|
|
0a536245f3 | ||
|
|
edfa9ecc07 | ||
|
|
f4982c85ca | ||
|
|
3ce771d587 | ||
|
|
72d6b446c3 | ||
|
|
40d694eec8 | ||
|
|
6af1423666 | ||
|
|
23a01347f1 | ||
|
|
7c86d6163a | ||
|
|
d7233208f1 | ||
|
|
7f587ba720 | ||
|
|
21ecc1b675 | ||
|
|
6b13dc2b87 | ||
|
|
bb89184212 | ||
|
|
56338caaca | ||
|
|
d7e2ff8ac9 | ||
|
|
582ec0a1f9 | ||
|
|
53785f5644 | ||
|
|
a8acadb8f1 | ||
|
|
23dbda302e | ||
|
|
7e7ab4275d | ||
|
|
a455a3d98d | ||
|
|
588d987c25 | ||
|
|
8ffd06343a | ||
|
|
76207c443c | ||
|
|
7e9e0fac07 | ||
|
|
1fdbc7cce9 | ||
|
|
312369b200 | ||
|
|
c030174bfb | ||
|
|
faf466e79a | ||
|
|
856ffc1b72 | ||
|
|
c0924af06b | ||
|
|
33cec61a13 | ||
|
|
854ff696d8 | ||
|
|
cc3435d13d | ||
|
|
5ceaac195d | ||
|
|
5d5df977a6 | ||
|
|
245e85ef36 | ||
|
|
b96df6f14f | ||
|
|
1932c1e138 | ||
|
|
f7ee012be3 | ||
|
|
b49e11bc79 | ||
|
|
f709a11dfb | ||
|
|
17ed2240d3 | ||
|
|
a8b5107b1a | ||
|
|
735bab5d26 | ||
|
|
86f7876f50 | ||
|
|
46c96bc7ec |
@@ -1,5 +1,12 @@
|
||||
#!/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
|
||||
BRANCH=`git rev-parse --abbrev-ref HEAD`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
tasks:
|
||||
- init: |
|
||||
nvm install --lts
|
||||
npm i -g @sasjs/cli
|
||||
- init: npm install -g npm
|
||||
- command: npm i
|
||||
- command: 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
|
||||
|
||||
@@ -217,6 +217,15 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
|
||||
|
||||

|
||||
|
||||
## 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 -->
|
||||
|
||||
31
base/mf_deletefile.sas
Normal file
31
base/mf_deletefile.sas
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
@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;
|
||||
@@ -9,19 +9,17 @@
|
||||
|
||||
%put %mf_existfeature(PROCLUA);
|
||||
|
||||
@param feature the feature to detect. Leave blank to list all in log.
|
||||
@param [in] feature The feature to detect.
|
||||
|
||||
@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);
|
||||
@@ -29,7 +27,11 @@
|
||||
%let platform=%mf_getplatform();
|
||||
|
||||
%if &feature= %then %do;
|
||||
%put Supported features: PROCLUA;
|
||||
%put No feature was requested for detection;
|
||||
%end;
|
||||
%else %if &feature=COLCONSTRAINTS %then %do;
|
||||
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then 0;
|
||||
%else 1;
|
||||
%end;
|
||||
%else %if &feature=PROCLUA %then %do;
|
||||
/* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */
|
||||
@@ -43,5 +45,4 @@
|
||||
%put &sysmacroname: &feature not found;
|
||||
%end;
|
||||
%mend mf_existfeature;
|
||||
|
||||
/** @endcond */
|
||||
/** @endcond */
|
||||
|
||||
@@ -28,15 +28,17 @@
|
||||
be 8 characters, so a 7 letter prefix would mean `maxtries` should be 10.
|
||||
if using zero (0) as the prefix, a native assignment is used.
|
||||
@param [in] maxtries= (1000) the last part of the libref. Must be an integer.
|
||||
@param [in] lrecl= (32767) Provide a default lrecl with which to initialise
|
||||
the generated fileref.
|
||||
|
||||
@version 9.2
|
||||
@author Allan Bowe
|
||||
**/
|
||||
|
||||
%macro mf_getuniquefileref(prefix=_,maxtries=1000);
|
||||
%macro mf_getuniquefileref(prefix=_,maxtries=1000,lrecl=32767);
|
||||
%local rc fname;
|
||||
%if &prefix=0 %then %do;
|
||||
%let rc=%sysfunc(filename(fname,,temp));
|
||||
%let rc=%sysfunc(filename(fname,,temp,lrecl=&lrecl));
|
||||
%if &rc %then %put %sysfunc(sysmsg());
|
||||
&fname
|
||||
%end;
|
||||
@@ -47,7 +49,7 @@
|
||||
%do x=0 %to &maxtries;
|
||||
%let fname=&prefix%substr(%sysfunc(ranuni(0)),3,&len);
|
||||
%if %sysfunc(fileref(&fname)) > 0 %then %do;
|
||||
%let rc=%sysfunc(filename(fname,,temp));
|
||||
%let rc=%sysfunc(filename(fname,,temp,lrecl=&lrecl));
|
||||
%if &rc %then %put %sysfunc(sysmsg());
|
||||
&fname
|
||||
%return;
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
%else %if %symexist(&metavar) %then %do;
|
||||
%if %length(&&&metavar)=0 %then %let user=&sysuserid;
|
||||
/* sometimes SAS will add @domain extension - remove for consistency */
|
||||
%else %let user=%scan(&&&metavar,1,@);
|
||||
/* but be sure to quote in case of usernames with commas */
|
||||
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@));
|
||||
%end;
|
||||
%else %let user=&sysuserid;
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
|
||||
%macro mf_isint(arg
|
||||
)/*/STORE SOURCE*/;
|
||||
/* remove minus sign if exists */
|
||||
|
||||
/* blank val is not an integer */
|
||||
%if "&arg"="" %then %do;0%return;%end;
|
||||
|
||||
/* remove minus sign if exists */
|
||||
%local val;
|
||||
%if "%substr(%str(&arg),1,1)"="-" %then %let val=%substr(%str(&arg),2);
|
||||
%else %let val=&arg;
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
%goto exit_success;
|
||||
%exit_err:
|
||||
%put %str(ERR)OR: &abortmsg;
|
||||
%put &abortmsg;
|
||||
%mf_abort(iftrue=(&mabort ne SOFT),
|
||||
mac=mf_verifymacvars,
|
||||
msg=%str(&abortmsg)
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
%end;
|
||||
|
||||
/* Stored Process Server web app context */
|
||||
%if %symexist(_metaperson)
|
||||
%if %symexist(_METAFOLDER)
|
||||
or "&SYSPROCESSNAME "="Compute Server "
|
||||
or &mode=INCLUDE
|
||||
%then %do;
|
||||
@@ -161,12 +161,14 @@
|
||||
/* send response in SASjs JSON format */
|
||||
data _null_;
|
||||
file _webout mod lrecl=32000 encoding='utf-8';
|
||||
length msg $32767 ;
|
||||
length msg syswarningtext syserrortext $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 */
|
||||
@@ -260,4 +262,4 @@
|
||||
%end;
|
||||
%mend mp_abort;
|
||||
|
||||
/** @endcond */
|
||||
/** @endcond */
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
proc compare
|
||||
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
|
||||
compare=&ds;
|
||||
compare=&ds noprint;
|
||||
run;
|
||||
|
||||
%if &sysinfo=0 %then %do;
|
||||
|
||||
194
base/mp_chop.sas
Normal file
194
base/mp_chop.sas
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
@file
|
||||
@brief Splits a file of ANY SIZE by reference to a search string.
|
||||
@details Provide a fileref and a search string to chop off part of a file.
|
||||
|
||||
Works by reading in the file byte by byte, then marking the beginning and end
|
||||
of each matched string, before finally doing the chop.
|
||||
|
||||
Choose whether to keep the FIRST or the LAST section of the file. Optionally,
|
||||
use an OFFSET to fix the precise chop point.
|
||||
|
||||
Usage:
|
||||
|
||||
%let src="%sysfunc(pathname(work))/file.txt";
|
||||
%let str=Chop here!;
|
||||
%let out1="%sysfunc(pathname(work))/file1.txt";
|
||||
%let out2="%sysfunc(pathname(work))/file2.txt";
|
||||
%let out3="%sysfunc(pathname(work))/file3.txt";
|
||||
%let out4="%sysfunc(pathname(work))/file4.txt";
|
||||
|
||||
data _null_;
|
||||
file &src;
|
||||
put "startsection&str.endsection";
|
||||
run;
|
||||
|
||||
%mp_chop(&src, matchvar=str, keep=FIRST, outfile=&out1)
|
||||
%mp_chop(&src, matchvar=str, keep=LAST, outfile=&out2)
|
||||
%mp_chop(&src, matchvar=str, keep=FIRST, matchpoint=END, outfile=&out3)
|
||||
%mp_chop(&src, matchvar=str, keep=LAST, matchpoint=END, outfile=&out4)
|
||||
|
||||
filename results (&out1 &out2 &out3 &out4);
|
||||
data _null_;
|
||||
infile results;
|
||||
input;
|
||||
list;
|
||||
run;
|
||||
|
||||
Results:
|
||||
@li `startsection`
|
||||
@li `Chop here!endsection`
|
||||
@li `startsectionChop here!`
|
||||
@li `endsection`
|
||||
|
||||
For more examples, see mp_chop.test.sas
|
||||
|
||||
@param [in] infile The QUOTED path to the file on which to perform the chop
|
||||
@param [in] matchvar= Macro variable NAME containing the string to split by
|
||||
@param [in] matchpoint= (START) Valid values:
|
||||
@li START - chop at the beginning of the string in `matchvar`.
|
||||
@li END - chop at the end of the string in `matchvar`.
|
||||
@param [in] offset= (0) An adjustment to the precise chop location, by
|
||||
by reference to the `matchpoint`. Should be a positive or negative integer.
|
||||
@param [in] keep= (FIRST) Valid values:
|
||||
@li FIRST - keep the section of the file before the chop
|
||||
@li LAST - keep the section of the file after the chop
|
||||
@param [in] mdebug= (0) Set to 1 to provide macro debugging
|
||||
@param outfile= (0) Optional QUOTED path to the adjusted output file (avoids
|
||||
overwriting the first file).
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquename.sas
|
||||
|
||||
<h4> Related Macros </h4>
|
||||
@li mp_abort.sas
|
||||
@li mp_gsubfile.sas
|
||||
@li mp_replace.sas
|
||||
@li mp_chop.test.sas
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
|
||||
**/
|
||||
|
||||
%macro mp_chop(infile,
|
||||
matchvar=,
|
||||
matchpoint=START,
|
||||
keep=FIRST,
|
||||
offset=0,
|
||||
mdebug=0,
|
||||
outfile=0
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%local fref0 dttm ds1 outref;
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let ds1=%mf_getuniquename(prefix=allchars);
|
||||
%let ds2=%mf_getuniquename(prefix=startmark);
|
||||
|
||||
%if &outfile=0 %then %let outfile=&infile;
|
||||
|
||||
%mp_abort(iftrue= (%length(%superq(&matchvar))=0)
|
||||
,mac=mp_chop.sas
|
||||
,msg=%str(&matchvar is an empty variable)
|
||||
)
|
||||
|
||||
/* START */
|
||||
%let dttm=%sysfunc(datetime());
|
||||
|
||||
filename &fref0 &infile lrecl=1 recfm=n;
|
||||
|
||||
/* create dataset with one char per row */
|
||||
data &ds1;
|
||||
infile &fref0;
|
||||
input sourcechar $char1. @@;
|
||||
format sourcechar hex2.;
|
||||
run;
|
||||
|
||||
/* get start & stop position of first matchvar string (one row, two vars) */
|
||||
data &ds2;
|
||||
/* set find string to length in bytes to cover trailing spaces */
|
||||
length string $ %length(%superq(&matchvar));
|
||||
string =symget("&matchvar");
|
||||
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;
|
||||
/* matched! */
|
||||
stop;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
stop;
|
||||
keep START STOP;
|
||||
run;
|
||||
|
||||
%local split;
|
||||
%let split=0;
|
||||
data _null_;
|
||||
set &ds2;
|
||||
if "&matchpoint"='START' then do;
|
||||
if "&keep"='FIRST' then mp=start;
|
||||
else if "&keep"='LAST' then mp=start-1;
|
||||
end;
|
||||
else if "&matchpoint"='END' then do;
|
||||
if "&keep"='FIRST' then mp=stop+1;
|
||||
else if "&keep"='LAST' then mp=stop;
|
||||
end;
|
||||
split=mp+&offset;
|
||||
call symputx('split',split,'l');
|
||||
%if &mdebug=1 %then %do;
|
||||
put (_all_)(=);
|
||||
%put &=offset;
|
||||
%end;
|
||||
run;
|
||||
%if &split=0 %then %do;
|
||||
%put &sysmacroname: No match found in &infile for string %superq(&matchvar);
|
||||
%return;
|
||||
%end;
|
||||
|
||||
data _null_;
|
||||
file &outfile recfm=n;
|
||||
set &ds1;
|
||||
%if &keep=FIRST %then %do;
|
||||
if _n_ ge &split then stop;
|
||||
%end;
|
||||
%else %do;
|
||||
if _n_ gt &split;
|
||||
%end;
|
||||
put sourcechar char1.;
|
||||
run;
|
||||
|
||||
%if &mdebug=0 %then %do;
|
||||
filename &fref0 clear;
|
||||
%end;
|
||||
%else %do;
|
||||
data _null_;
|
||||
infile &outfile lrecl=32767;
|
||||
input;
|
||||
list;
|
||||
if _n_>50 then stop;
|
||||
run;
|
||||
%end;
|
||||
/* END */
|
||||
%put &sysmacroname took %sysevalf(%sysfunc(datetime())-&dttm) seconds to run;
|
||||
|
||||
%mend mp_chop;
|
||||
@@ -29,6 +29,7 @@ Usage:
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getplatform.sas
|
||||
@li mm_createwebservice.sas
|
||||
@li ms_createwebservice.sas
|
||||
@li mv_createwebservice.sas
|
||||
|
||||
@param [in,out] path= The full folder path where the service will be created
|
||||
@@ -40,7 +41,7 @@ Usage:
|
||||
be added
|
||||
@param [in] replace= (YES) Select YES to replace any existing service in that
|
||||
location
|
||||
|
||||
@param [in] mDebug= (0) set to 1 to show debug messages in the log
|
||||
|
||||
@version 9.2
|
||||
@author Allan Bowe
|
||||
@@ -53,6 +54,7 @@ Usage:
|
||||
,code=ft15f001
|
||||
,desc=This service was created by the mp_createwebservice macro
|
||||
,replace=YES
|
||||
,mdebug=0
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%if &syscc ge 4 %then %do;
|
||||
@@ -71,8 +73,17 @@ Usage:
|
||||
,replace=&replace
|
||||
)
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%if "&path"="HOME" %then %let path=/Users/&_sasjs_username/My Folder;
|
||||
%ms_createwebservice(path=&path
|
||||
,name=&name
|
||||
,code=&code
|
||||
,precode=&precode
|
||||
,mdebug=&mdebug
|
||||
)
|
||||
%end;
|
||||
%else %do;
|
||||
%if "&path"="HOME" %then %let path=/User Folders/&sysuserid/My Folder;
|
||||
%if "&path"="HOME" %then %let path=/User Folders/&_METAPERSON/My Folder;
|
||||
%mm_createwebservice(path=&path
|
||||
,name=&name
|
||||
,code=&code
|
||||
|
||||
@@ -94,6 +94,13 @@ 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;
|
||||
@@ -101,12 +108,6 @@ 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;
|
||||
@@ -151,6 +152,7 @@ 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;
|
||||
@@ -242,4 +244,4 @@ run;
|
||||
proc sql;
|
||||
drop table &out_ds;
|
||||
|
||||
%mend mp_dirlist;
|
||||
%mend mp_dirlist;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
@version 9.2
|
||||
@author Allan Bowe
|
||||
@cond
|
||||
**/
|
||||
|
||||
%macro mp_ds2cards(base_ds=, tgt_ds=
|
||||
@@ -219,7 +220,8 @@ data _null_;
|
||||
put ' @file';
|
||||
put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset";
|
||||
put " @details Generated by %nrstr(%%)mp_ds2cards()";
|
||||
put " Available on github.com/sasjs/core";
|
||||
put " Source: https://github.com/sasjs/core";
|
||||
put ' @cond ';
|
||||
put '**/';
|
||||
put "data &tgt_ds &indexes;";
|
||||
put "attrib ";
|
||||
@@ -264,6 +266,7 @@ data _null_;
|
||||
if __lastobs then do;
|
||||
put ';;;;';
|
||||
put 'run;';
|
||||
put '/** @endcond **/';
|
||||
stop;
|
||||
end;
|
||||
run;
|
||||
@@ -283,4 +286,5 @@ quit;
|
||||
%put NOTE-;%put NOTE-;
|
||||
%put NOTE- %sysfunc(dequote(&cards_file.));
|
||||
%put NOTE-;%put NOTE-;
|
||||
%mend mp_ds2cards;
|
||||
%mend mp_ds2cards;
|
||||
/** @endcond **/
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
|
||||
%local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks;
|
||||
%local engine schema ds1 ds2 ds3 dsn tabs1 tabs2 sum pk4sure pkdefault finalpks
|
||||
pkfromindex;
|
||||
|
||||
%let lib=%upcase(&lib);
|
||||
%let ds=%upcase(&ds);
|
||||
@@ -70,6 +71,7 @@
|
||||
%let sum=%mf_getuniquename(prefix=getpk_sum);
|
||||
%let pk4sure=%mf_getuniquename(prefix=getpk_pk4sure);
|
||||
%let pkdefault=%mf_getuniquename(prefix=getpk_pkdefault);
|
||||
%let pkfromindex=%mf_getuniquename(prefix=getpk_pkfromindex);
|
||||
%let finalpks=%mf_getuniquename(prefix=getpk_finalpks);
|
||||
|
||||
%local dbg;
|
||||
@@ -180,9 +182,23 @@ create table &ds1 as
|
||||
and a.constraint_name=b.constraint_name
|
||||
order by 1,2,3,4;
|
||||
|
||||
/* extract cols from the relevant unique INDEXES */
|
||||
create table &pkfromindex as
|
||||
select libname as libref
|
||||
,memname as table_name
|
||||
,indxname as constraint_name
|
||||
,indxpos as constraint_order
|
||||
,name
|
||||
from dictionary.indexes
|
||||
where nomiss='yes' and unique='yes' and upcase(libname)="&lib"
|
||||
%if &ds ne 0 %then %do;
|
||||
and upcase(memname)="&ds"
|
||||
%end;
|
||||
order by 1,2,3,4;
|
||||
|
||||
/* create one table */
|
||||
data &finalpks;
|
||||
set &pkdefault &pk4sure ;
|
||||
set &pkdefault &pk4sure &pkfromindex;
|
||||
pk_ind=1;
|
||||
/* if there are multiple unique constraints, take the first */
|
||||
by libref table_name constraint_name;
|
||||
@@ -256,4 +272,4 @@ create table &outds as
|
||||
iftrue=(&mdebug=0)
|
||||
)
|
||||
|
||||
%mend mp_getpk;
|
||||
%mend mp_getpk;
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
outfile=0
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%if "%substr(&sysver.XX,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;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
@file
|
||||
@brief Returns a unique hash for a dataset
|
||||
@details Ignores metadata attributes, used only to hash values. Compared
|
||||
datasets must be in the same order.
|
||||
@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.
|
||||
|
||||
%mp_hashdataset(sashelp.class,outds=myhash)
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
@li mf_getattrn.sas
|
||||
@li mf_getuniquename.sas
|
||||
@li mf_getvarlist.sas
|
||||
@li mf_getvartype.sas
|
||||
@li mp_md5.sas
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li mp_hashdataset.test.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.|
|
||||
|---|
|
||||
@@ -35,48 +38,48 @@
|
||||
|
||||
%macro mp_hashdataset(
|
||||
libds,
|
||||
outds=,
|
||||
outds=work._data_,
|
||||
salt=,
|
||||
iftrue=%str(1=1)
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||
%local keyvar /* roll up the md5 */
|
||||
prevkeyvar /* retain prev record md5 */
|
||||
lastvar /* last var in input ds */
|
||||
cvars nvars;
|
||||
|
||||
%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;
|
||||
%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;
|
||||
|
||||
@@ -73,4 +73,4 @@ options
|
||||
%end;
|
||||
;
|
||||
|
||||
%mend mp_init;
|
||||
%mend mp_init;
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
%if &action=OPEN %then %do;
|
||||
options nobomfile;
|
||||
data _null_;file &jref encoding='utf-8' ;
|
||||
data _null_;file &jref encoding='utf-8' lrecl=200;
|
||||
put '{"PROCESSED_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '"';
|
||||
run;
|
||||
%end;
|
||||
@@ -199,12 +199,23 @@
|
||||
format _numeric_ bart.;
|
||||
%do i=1 %to &numcols;
|
||||
%if &&typelong&i=char or &fmt=Y %then %do;
|
||||
&&name&i='"'!!trim(prxchange('s/"/\"/',-1,
|
||||
prxchange('s/'!!'0A'x!!'/\n/',-1,
|
||||
prxchange('s/'!!'0D'x!!'/\r/',-1,
|
||||
prxchange('s/'!!'09'x!!'/\t/',-1,
|
||||
prxchange('s/\\/\\\\/',-1,&&name&i)
|
||||
)))))!!'"';
|
||||
if findc(&&name&i,'"\'!!'0A0D09000E0F01021011'x) then do;
|
||||
&&name&i='"'!!trim(
|
||||
prxchange('s/"/\\"/',-1, /* double quote */
|
||||
prxchange('s/\x0A/\n/',-1, /* new line */
|
||||
prxchange('s/\x0D/\r/',-1, /* carriage return */
|
||||
prxchange('s/\x09/\\t/',-1, /* tab */
|
||||
prxchange('s/\x00/\\u0000/',-1, /* NUL */
|
||||
prxchange('s/\x0E/\\u000E/',-1, /* SS */
|
||||
prxchange('s/\x0F/\\u000F/',-1, /* SF */
|
||||
prxchange('s/\x01/\\u0001/',-1, /* SOH */
|
||||
prxchange('s/\x02/\\u0002/',-1, /* STX */
|
||||
prxchange('s/\x10/\\u0010/',-1, /* DLE */
|
||||
prxchange('s/\x11/\\u0011/',-1, /* DC1 */
|
||||
prxchange('s/\\/\\\\/',-1,&&name&i)
|
||||
))))))))))))!!'"';
|
||||
end;
|
||||
else &&name&i=quote(cats(&&name&i));
|
||||
%end;
|
||||
%end;
|
||||
run;
|
||||
|
||||
@@ -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 fmtname into: fmtlist separated by ' ' from &libds;
|
||||
select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
|
||||
|
||||
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
|
||||
|
||||
@@ -144,8 +144,11 @@ select distinct 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';
|
||||
@@ -156,7 +159,6 @@ data &inlibds;
|
||||
end;
|
||||
run;
|
||||
|
||||
|
||||
/**
|
||||
* Identify new records
|
||||
*/
|
||||
@@ -263,7 +265,7 @@ options ibufsize=&ibufsize;
|
||||
%end;
|
||||
|
||||
%mp_storediffs(&libcat-FC
|
||||
,&inlibds
|
||||
,&base_fmts
|
||||
,FMTNAME START
|
||||
,delds=&outds_del
|
||||
,modds=&outds_mod
|
||||
@@ -272,6 +274,9 @@ 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,.)
|
||||
@@ -295,4 +300,4 @@ options ibufsize=&ibufsize;
|
||||
%put &sysmacroname exit vars:;
|
||||
%put _local_;
|
||||
%end;
|
||||
%mend mp_loadformat;
|
||||
%mend mp_loadformat;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
@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
|
||||
@param outfile= (0) Optional QUOTED path to the adjusted output file (to
|
||||
avoid overwriting the first file).
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@@ -43,7 +43,9 @@
|
||||
@li mf_getuniquename.sas
|
||||
|
||||
<h4> Related Macros </h4>
|
||||
@li mp_gsubfile.test.sas
|
||||
@li mp_chop.sas
|
||||
@li mp_gsubfile.sas
|
||||
@li mp_replace.test.sas
|
||||
|
||||
@version 9.4
|
||||
@author Bartosz Jabłoński
|
||||
@@ -70,7 +72,7 @@ filename &inref &infile lrecl=1 recfm=n;
|
||||
|
||||
data &ds1;
|
||||
infile &inref;
|
||||
input sourcechar $ 1. @@;
|
||||
input sourcechar $char1. @@;
|
||||
format sourcechar hex2.;
|
||||
run;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
@file
|
||||
@brief Streams a file to _webout according to content type
|
||||
@details Will set headers using appropriate functions (SAS 9 vs Viya) and send
|
||||
content as a binary stream.
|
||||
@details Will set headers using appropriate functions per the server type
|
||||
(Viya, EBI, [SASjs Server](https://github.com/sasjs/server)) and stream
|
||||
content using mp_binarycopy().
|
||||
|
||||
Usage:
|
||||
|
||||
@@ -12,7 +13,14 @@
|
||||
|
||||
%mp_streamfile(contenttype=csv,inloc=/some/where.txt,outname=myfile.txt)
|
||||
|
||||
@param [in] contenttype= (TEXT) Either TEXT, ZIP, CSV, EXCEL
|
||||
@param [in] contenttype= (TEXT) Supported:
|
||||
@li CSV
|
||||
@li EXCEL
|
||||
@li MARKDOWN
|
||||
@li TEXT
|
||||
@li ZIP
|
||||
Feel free to submit PRs to support more mime types! The official list is
|
||||
here: https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||
@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.
|
||||
@@ -58,7 +66,7 @@ run;
|
||||
%if &contentype=CSV %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type','application/csv');
|
||||
rc=stpsrv_header('Content-Type','application/csv');
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
%end;
|
||||
@@ -68,7 +76,7 @@ run;
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,application/csv)
|
||||
%mfs_httpheader(Content-Type,application/csv)
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
%end;
|
||||
%end;
|
||||
@@ -76,7 +84,7 @@ run;
|
||||
/* suitable for XLS format */
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type','application/vnd.ms-excel');
|
||||
rc=stpsrv_header('Content-Type','application/vnd.ms-excel');
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
%end;
|
||||
@@ -86,14 +94,14 @@ run;
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,application/vnd.ms-excel)
|
||||
%mfs_httpheader(Content-Type,application/vnd.ms-excel)
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
%end;
|
||||
%end;
|
||||
%else %if &contentype=GIF or &contentype=JPEG or &contentype=PNG %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type',"image/%lowcase(&contenttype)");
|
||||
rc=stpsrv_header('Content-Type',"image/%lowcase(&contenttype)");
|
||||
run;
|
||||
%end;
|
||||
%else %if &platform=SASVIYA %then %do;
|
||||
@@ -101,22 +109,30 @@ run;
|
||||
contenttype="image/%lowcase(&contenttype)";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,image/%lowcase(&contenttype))
|
||||
%mfs_httpheader(Content-Type,image/%lowcase(&contenttype))
|
||||
%end;
|
||||
%end;
|
||||
%else %if &contentype=HTML %then %do;
|
||||
%if &platform=SASVIYA %then %do;
|
||||
%else %if &contentype=HTML or &contenttype=MARKDOWN %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-Type',"text/%lowcase(&contenttype)");
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
%end;
|
||||
%else %if &platform=SASVIYA %then %do;
|
||||
filename &outref filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.json"
|
||||
contenttype="text/html";
|
||||
contenttype="text/%lowcase(&contenttype)"
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,text/html)
|
||||
%mfs_httpheader(Content-Type,text/%lowcase(&contenttype))
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
%end;
|
||||
%end;
|
||||
%else %if &contentype=TEXT %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type','application/text');
|
||||
rc=stpsrv_header('Content-Type','application/text');
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
%end;
|
||||
@@ -126,14 +142,14 @@ run;
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,application/text)
|
||||
%mfs_httpheader(Content-Type,application/text)
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
%end;
|
||||
%end;
|
||||
%else %if &contentype=WOFF or &contentype=WOFF2 or &contentype=TTF %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type',"font/%lowcase(&contenttype)");
|
||||
rc=stpsrv_header('Content-Type',"font/%lowcase(&contenttype)");
|
||||
run;
|
||||
%end;
|
||||
%else %if &platform=SASVIYA %then %do;
|
||||
@@ -141,13 +157,13 @@ run;
|
||||
contenttype="font/%lowcase(&contenttype)";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,font/%lowcase(&contenttype))
|
||||
%mfs_httpheader(Content-Type,font/%lowcase(&contenttype))
|
||||
%end;
|
||||
%end;
|
||||
%else %if &contentype=XLSX %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type',
|
||||
rc=stpsrv_header('Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
@@ -159,7 +175,7 @@ run;
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type
|
||||
%mfs_httpheader(Content-Type
|
||||
,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
)
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
@@ -168,7 +184,7 @@ run;
|
||||
%else %if &contentype=ZIP %then %do;
|
||||
%if (&platform=SASMETA and &streamweb=1) %then %do;
|
||||
data _null_;
|
||||
rc=stpsrv_header('Content-type','application/zip');
|
||||
rc=stpsrv_header('Content-Type','application/zip');
|
||||
rc=stpsrv_header('Content-disposition',"attachment; filename=&outname");
|
||||
run;
|
||||
%end;
|
||||
@@ -178,7 +194,7 @@ run;
|
||||
contentdisp="attachment; filename=&outname";
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
%mfs_httpheader(Content-type,application/zip)
|
||||
%mfs_httpheader(Content-Type,application/zip)
|
||||
%mfs_httpheader(Content-disposition,%str(attachment; filename=&outname))
|
||||
%end;
|
||||
%end;
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_abort.sas
|
||||
@li mp_binarycopy.sas
|
||||
@li mp_chop.sas
|
||||
@li mp_ds2csv.sas
|
||||
@li ms_testservice.sas
|
||||
@li mv_getjobresult.sas
|
||||
@li mv_jobflow.sas
|
||||
|
||||
@@ -63,7 +65,7 @@
|
||||
viyaresult=WEBOUT_JSON,
|
||||
viyacontext=SAS Job Execution compute context
|
||||
)/*/STORE SOURCE*/;
|
||||
%local dbg pcnt fref1 webref i webcount var platform;
|
||||
%local dbg pcnt fref1 fref2 webref webrefpath i webcount var platform;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname entry vars:;
|
||||
%put _local_;
|
||||
@@ -104,10 +106,14 @@
|
||||
%end;
|
||||
%end;
|
||||
|
||||
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let webref=%mf_getuniquefileref();
|
||||
%let platform=%mf_getplatform();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let fref2=%mf_getuniquefileref();
|
||||
%let webref=%mf_getuniquefileref();
|
||||
%let webrefpath=%sysfunc(pathname(work))/%mf_getuniquename();
|
||||
/* mp_chop requires a physical path as input */
|
||||
filename &webref "&webrefpath";
|
||||
|
||||
%if &platform=SASMETA %then %do;
|
||||
|
||||
/* parse the input files */
|
||||
@@ -262,13 +268,30 @@
|
||||
mdebug=&mdebug
|
||||
)
|
||||
|
||||
%end;
|
||||
%else %if &platform=SASJS %then %do;
|
||||
|
||||
%ms_testservice(&program
|
||||
,inputfiles=&inputfiles
|
||||
,inputdatasets=&inputdatasets
|
||||
,inputparams=&inputparams
|
||||
,debug=&debug
|
||||
,mdebug=&mdebug
|
||||
,outlib=&outlib
|
||||
,outref=&outref
|
||||
)
|
||||
|
||||
%end;
|
||||
%else %do;
|
||||
%put %str(ERR)OR: Unrecognised platform: &platform;
|
||||
%end;
|
||||
|
||||
%if &mdebug=0 %then %do;
|
||||
filename &webref clear;
|
||||
filename &fref1 clear;
|
||||
%if &platform ne SASJS %then %do;
|
||||
filename &fref2 clear;
|
||||
filename &webref clear;
|
||||
%end;
|
||||
%end;
|
||||
%else %do;
|
||||
%put &sysmacroname exit vars:;
|
||||
|
||||
77
build.py
77
build.py
@@ -4,8 +4,8 @@ from pathlib import Path
|
||||
# Prepare Lua Macros
|
||||
files = [f for f in Path('lua').iterdir() if f.match("*.lua")]
|
||||
for file in files:
|
||||
basename=os.path.basename(file)
|
||||
name='ml_' + os.path.splitext(basename)[0]
|
||||
basename = os.path.basename(file)
|
||||
name = 'ml_' + os.path.splitext(basename)[0]
|
||||
ml = open('lua/' + name + '.sas', "w")
|
||||
ml.write("/**\n")
|
||||
ml.write(" @file " + name + '.sas\n')
|
||||
@@ -20,50 +20,68 @@ for file in files:
|
||||
ml.write(" file \"%sysfunc(pathname(work))/" + name + ".lua\";\n")
|
||||
with open(file) as infile:
|
||||
for line in infile:
|
||||
ml.write(" put '" + line.rstrip().replace("'","''") + " ';\n")
|
||||
ml.write(" put '" + line.rstrip().replace("'", "''") + " ';\n")
|
||||
ml.write("run;\n\n")
|
||||
ml.write("%inc \"%sysfunc(pathname(work))/" + name + ".lua\" /source2;\n\n")
|
||||
|
||||
ml.write("/* ensure big enough lrecl to avoid lua compilation issues */\n")
|
||||
ml.write("%local optval;\n")
|
||||
ml.write("%let optval=%sysfunc(getoption(lrecl));\n")
|
||||
ml.write("options lrecl=1024;\n\n")
|
||||
ml.write("/* execute the lua code by using a .lua extension */\n")
|
||||
ml.write("%inc \"%sysfunc(pathname(work))/" +
|
||||
name + ".lua\" /source2;\n\n")
|
||||
ml.write("options lrecl=&optval;\n\n")
|
||||
ml.write("%mend " + name + ";\n")
|
||||
|
||||
ml.close()
|
||||
|
||||
# prepare web files
|
||||
files=['viya/mv_createwebservice.sas','meta/mm_createwebservice.sas']
|
||||
files = ['viya/mv_createwebservice.sas',
|
||||
'meta/mm_createwebservice.sas', 'server/ms_createwebservice.sas']
|
||||
for file in files:
|
||||
webout0=open('base/mp_jsonout.sas','r')
|
||||
if file=='viya/mv_createwebservice.sas':
|
||||
webout1=open('viya/mv_webout.sas',"r")
|
||||
webout0 = open('base/mp_jsonout.sas', 'r')
|
||||
webout1 = open('base/mf_getuser.sas', 'r')
|
||||
|
||||
if file == 'viya/mv_createwebservice.sas':
|
||||
webout2 = open('viya/mv_webout.sas', "r")
|
||||
weboutfiles = [webout0, webout1, webout2]
|
||||
elif file == 'server/ms_createwebservice.sas':
|
||||
webout2 = open('server/ms_webout.sas', "r")
|
||||
webout3 = open('server/mfs_httpheader.sas', 'r')
|
||||
weboutfiles = [webout0, webout1, webout2, webout3]
|
||||
else:
|
||||
webout1=open('meta/mm_webout.sas','r')
|
||||
webout2=open('base/mf_getuser.sas','r')
|
||||
outfile=open(file + 'TEMP','w')
|
||||
infile=open(file,'r')
|
||||
delrow=0
|
||||
webout2 = open('meta/mm_webout.sas', 'r')
|
||||
weboutfiles = [webout0, webout1, webout2]
|
||||
outfile = open(file + 'TEMP', 'w')
|
||||
infile = open(file, 'r')
|
||||
delrow = 0
|
||||
for line in infile:
|
||||
if line=='/* WEBOUT BEGIN */\n':
|
||||
delrow=1
|
||||
if line == '/* WEBOUT BEGIN */\n':
|
||||
delrow = 1
|
||||
outfile.write('/* WEBOUT BEGIN */\n')
|
||||
weboutfiles=[webout0,webout1,webout2]
|
||||
for weboutfile in weboutfiles:
|
||||
stripcomment=1
|
||||
stripcomment = 1
|
||||
for w in weboutfile:
|
||||
if w=='**/\n': stripcomment=0
|
||||
elif stripcomment==0:
|
||||
outfile.write(" put '" + w.rstrip().replace("'","''") + " ';\n")
|
||||
elif delrow==1 and line=='/* WEBOUT END */\n':
|
||||
delrow=0
|
||||
outfile.write('/* WEBOUT END */\n')
|
||||
elif delrow==0:
|
||||
if w == '**/\n':
|
||||
stripcomment = 0
|
||||
elif stripcomment == 0:
|
||||
outfile.write(
|
||||
" put '" + w.rstrip().replace("'", "''") + " ';\n")
|
||||
elif delrow == 1 and line == '/* WEBOUT END */\n':
|
||||
delrow = 0
|
||||
outfile.write('/* WEBOUT END */\n')
|
||||
elif delrow == 0:
|
||||
outfile.write(line.rstrip() + "\n")
|
||||
webout0.close()
|
||||
webout1.close()
|
||||
webout2.close()
|
||||
outfile.close()
|
||||
infile.close()
|
||||
os.remove(file)
|
||||
os.rename(file + 'TEMP',file)
|
||||
os.rename(file + 'TEMP', file)
|
||||
|
||||
# Concatenate all macros into a single file
|
||||
header="""
|
||||
header = """
|
||||
/**
|
||||
@file
|
||||
@brief Auto-generated file
|
||||
@@ -84,14 +102,15 @@ options noquotelenmax;
|
||||
"""
|
||||
f = open('all.sas', "w") # r / r+ / rb / rb+ / w / wb
|
||||
f.write(header)
|
||||
folders=['base','ddl','meta','metax','server','viya','lua','fcmp']
|
||||
folders = ['base', 'ddl', 'meta', 'metax', 'server', 'viya', 'lua', 'fcmp']
|
||||
for folder in folders:
|
||||
filenames = [fn for fn in Path('./' + folder).iterdir() if fn.match("*.sas")]
|
||||
filenames = [fn for fn in Path(
|
||||
'./' + folder).iterdir() if fn.match("*.sas")]
|
||||
filenames.sort()
|
||||
with open('mc_' + folder + '.sas', 'w') as outfile:
|
||||
for fname in filenames:
|
||||
with open(fname) as infile:
|
||||
outfile.write(infile.read())
|
||||
with open('mc_' + folder + '.sas','r') as c:
|
||||
with open('mc_' + folder + '.sas', 'r') as c:
|
||||
f.write(c.read())
|
||||
f.close()
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
@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;
|
||||
@@ -39,6 +39,14 @@ data _null_;
|
||||
put 'io.close(file) ';
|
||||
run;
|
||||
|
||||
/* ensure big enough lrecl to avoid lua compilation issues */
|
||||
%local optval;
|
||||
%let optval=%sysfunc(getoption(lrecl));
|
||||
options lrecl=1024;
|
||||
|
||||
/* execute the lua code by using a .lua extension */
|
||||
%inc "%sysfunc(pathname(work))/ml_gsubfile.lua" /source2;
|
||||
|
||||
options lrecl=&optval;
|
||||
|
||||
%mend ml_gsubfile;
|
||||
|
||||
@@ -389,6 +389,14 @@ data _null_;
|
||||
put '-- JSON.LUA ENDS HERE ';
|
||||
run;
|
||||
|
||||
/* ensure big enough lrecl to avoid lua compilation issues */
|
||||
%local optval;
|
||||
%let optval=%sysfunc(getoption(lrecl));
|
||||
options lrecl=1024;
|
||||
|
||||
/* execute the lua code by using a .lua extension */
|
||||
%inc "%sysfunc(pathname(work))/ml_json.lua" /source2;
|
||||
|
||||
options lrecl=&optval;
|
||||
|
||||
%mend ml_json;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_abort.sas
|
||||
|
||||
@param libref the libref (not name) of the metadata library
|
||||
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
|
||||
@param [in] libref The libref (not name) of the metadata library
|
||||
@param [in] 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 $200;
|
||||
length liburi LibName msg $200;
|
||||
call missing(of _all_);
|
||||
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
|
||||
if nobj=1 then do;
|
||||
@@ -46,7 +46,24 @@
|
||||
* not always helpful though. One example, previously received:
|
||||
* NOTE: Libref XX refers to the same library metadata as libref XX.
|
||||
*/
|
||||
call symputx('msg',sysmsg(),'l');
|
||||
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');
|
||||
end;
|
||||
else do;
|
||||
@@ -65,20 +82,16 @@
|
||||
end;
|
||||
run;
|
||||
|
||||
%if &mp_abort=1 %then %do;
|
||||
%mp_abort(iftrue= (&mp_abort=1)
|
||||
,mac=mm_assignlib.sas
|
||||
,msg=&msg
|
||||
)
|
||||
%return;
|
||||
%end;
|
||||
%else %if %length(&msg)>2 %then %do;
|
||||
%put NOTE: &msg;
|
||||
%return;
|
||||
%end;
|
||||
%put NOTE: &msg;
|
||||
|
||||
%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;
|
||||
|
||||
@@ -103,7 +103,7 @@ data _null_;
|
||||
put ' ';
|
||||
put '%if &action=OPEN %then %do; ';
|
||||
put ' options nobomfile; ';
|
||||
put ' data _null_;file &jref encoding=''utf-8'' ; ';
|
||||
put ' data _null_;file &jref encoding=''utf-8'' lrecl=200; ';
|
||||
put ' put ''{"PROCESSED_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''"''; ';
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
@@ -232,12 +232,23 @@ data _null_;
|
||||
put ' format _numeric_ bart.; ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||
put ' &&name&i=''"''!!trim(prxchange(''s/"/\"/'',-1, ';
|
||||
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
|
||||
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
|
||||
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
|
||||
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
|
||||
put ' )))))!!''"''; ';
|
||||
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; ';
|
||||
put ' &&name&i=''"''!!trim( ';
|
||||
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
|
||||
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
|
||||
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
|
||||
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
|
||||
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
|
||||
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
|
||||
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
|
||||
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
|
||||
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
|
||||
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
|
||||
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
|
||||
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
|
||||
put ' ))))))))))))!!''"''; ';
|
||||
put ' end; ';
|
||||
put ' else &&name&i=quote(cats(&&name&i)); ';
|
||||
put ' %end; ';
|
||||
put ' %end; ';
|
||||
put ' run; ';
|
||||
@@ -303,6 +314,25 @@ data _null_;
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
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 ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
put ' %quote(&user) ';
|
||||
put ' ';
|
||||
put '%mend mf_getuser; ';
|
||||
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
|
||||
put ' ,showmeta=NO ';
|
||||
put '); ';
|
||||
@@ -421,14 +451,16 @@ data _null_;
|
||||
put ' put '',"_METAPERSON": '' _METAPERSON; ';
|
||||
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
|
||||
put ' put ",""SYSCC"" : ""&syscc"" "; ';
|
||||
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
|
||||
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
|
||||
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
|
||||
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
|
||||
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
|
||||
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
|
||||
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
|
||||
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
|
||||
put ' put '',"SYSVLONG" : '' sysvlong; ';
|
||||
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; ';
|
||||
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
|
||||
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
|
||||
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
|
||||
put ' length memsize $32; ';
|
||||
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
|
||||
@@ -442,24 +474,6 @@ data _null_;
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%mend mm_webout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
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 ' %else %let user=%scan(&&&metavar,1,@); ';
|
||||
put ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
put ' %quote(&user) ';
|
||||
put ' ';
|
||||
put '%mend mf_getuser; ';
|
||||
/* WEBOUT END */
|
||||
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
|
||||
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
||||
|
||||
@@ -78,6 +78,7 @@ 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;
|
||||
|
||||
@@ -49,20 +49,25 @@
|
||||
|
||||
|
||||
<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 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)
|
||||
|
||||
@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)
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
@@ -71,6 +76,7 @@
|
||||
|
||||
%macro mm_spkexport(metaloc=
|
||||
,secureref=
|
||||
,excludevars=0
|
||||
,outref=
|
||||
,cmdoutloc=%sysfunc(pathname(work))
|
||||
,cmdoutname=mmxport
|
||||
@@ -82,7 +88,7 @@
|
||||
%end;
|
||||
|
||||
/* set creds */
|
||||
%local mmxuser mmxpath;
|
||||
%local mmxuser mmxpath i var;
|
||||
%let mmxuser=$1;
|
||||
%let mmxpass=$2;
|
||||
%if %mf_isblank(&secureref)=0 %then %do;
|
||||
@@ -90,35 +96,51 @@
|
||||
%end;
|
||||
|
||||
/* setup metadata connection options */
|
||||
%local host port platform_object_path connx_string;
|
||||
%local host port platform_object_path ds;
|
||||
%let host=%sysfunc(getoption(metaserver));
|
||||
%let port=%sysfunc(getoption(metaport));
|
||||
%let platform_object_path=%mf_loc(POF);
|
||||
%let ds=%mf_getuniquename(prefix=spkexportable);
|
||||
|
||||
%let connx_string=%str(-host &host -port &port -user &mmxuser %trim(
|
||||
)-password &mmxpass);
|
||||
|
||||
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=exportable)
|
||||
%mm_tree(root=%str(&metaloc),types=EXPORTABLE ,outds=&ds)
|
||||
|
||||
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
|
||||
|
||||
data _null_;
|
||||
set exportable end=last;
|
||||
set &ds 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 &connx_string -disableX11 \";
|
||||
put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
|
||||
put "; ./ExportPackage -host &host -port &port -user &mmxuser \";
|
||||
put " -disableX11 -password &mmxpass \";
|
||||
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=&sysmacroname
|
||||
,mac=mm_spkexport
|
||||
,msg=%str(syscc=&syscc)
|
||||
)
|
||||
|
||||
%mend mm_spkexport;
|
||||
%mend mm_spkexport;
|
||||
|
||||
@@ -157,14 +157,16 @@
|
||||
put ',"_METAPERSON": ' _METAPERSON;
|
||||
put ',"_PROGRAM" : ' _PROGRAM ;
|
||||
put ",""SYSCC"" : ""&syscc"" ";
|
||||
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
|
||||
syserrortext=quote(cats(symget('SYSERRORTEXT')));
|
||||
put ',"SYSERRORTEXT" : ' syserrortext;
|
||||
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
|
||||
put ",""SYSJOBID"" : ""&sysjobid"" ";
|
||||
put ",""SYSSCPL"" : ""&sysscpl"" ";
|
||||
put ",""SYSSITE"" : ""&syssite"" ";
|
||||
sysvlong=quote(trim(symget('sysvlong')));
|
||||
put ',"SYSVLONG" : ' sysvlong;
|
||||
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
|
||||
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
|
||||
put ',"SYSWARNINGTEXT" : ' syswarningtext;
|
||||
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
|
||||
length memsize $32;
|
||||
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
|
||||
|
||||
2443
package-lock.json
generated
2443
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -26,14 +26,13 @@
|
||||
"homepage": "https://core.sasjs.io",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "sasjs cbd -t viya",
|
||||
"build": "sasjs cbd -t server",
|
||||
"docs": "sasjs doc -t docsonly && ./sasjs/utils/build.sh",
|
||||
"test": "sasjs test -t viya",
|
||||
"test": "sasjs test -t server",
|
||||
"lint": "sasjs lint",
|
||||
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sasjs/cli": "3.6.0",
|
||||
"@sasjs/core": "4.4.7"
|
||||
"@sasjs/cli": "3.13.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
"base",
|
||||
"ddl",
|
||||
"fcmp",
|
||||
"meta",
|
||||
"metax",
|
||||
"server",
|
||||
"viya",
|
||||
"lua",
|
||||
"server",
|
||||
"tests/crossplatform",
|
||||
"tests/ddl"
|
||||
],
|
||||
@@ -28,25 +25,20 @@
|
||||
"mcTestAppLoc": "/Public/temp/macrocore"
|
||||
}
|
||||
},
|
||||
"defaultTarget": "viya",
|
||||
"defaultTarget": "server",
|
||||
"targets": [
|
||||
{
|
||||
"name": "viya",
|
||||
"serverUrl": "https://sas.analytium.co.uk",
|
||||
"serverUrl": "",
|
||||
"serverType": "SASVIYA",
|
||||
"httpsAgentOptions": {
|
||||
"allowInsecureRequests": false
|
||||
},
|
||||
"appLoc": "/Public/temp/macrocore",
|
||||
"appLoc": "/Public/app/macrocore",
|
||||
"macroFolders": [
|
||||
"viya",
|
||||
"tests/viyaonly"
|
||||
],
|
||||
"programFolders": [],
|
||||
"binaryFolders": [],
|
||||
"deployConfig": {
|
||||
"deployServicePack": true,
|
||||
"deployScripts": []
|
||||
},
|
||||
"contextName": "SAS Job Execution compute context"
|
||||
},
|
||||
{
|
||||
@@ -58,6 +50,8 @@
|
||||
},
|
||||
"appLoc": "/Shared Data/temp/macrocore",
|
||||
"macroFolders": [
|
||||
"meta",
|
||||
"metax",
|
||||
"tests/sas9only"
|
||||
],
|
||||
"programFolders": [],
|
||||
@@ -71,30 +65,44 @@
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"serverUrl": "https://sas.analytium.co.uk:5000",
|
||||
"serverUrl": "https://sas.analytium.co.uk:5007",
|
||||
"serverType": "SASJS",
|
||||
"httpsAgentOptions": {
|
||||
"allowInsecureRequests": false
|
||||
},
|
||||
"appLoc": "/sasjs/core",
|
||||
"macroFolders": [
|
||||
"server",
|
||||
"tests/serveronly"
|
||||
],
|
||||
"programFolders": [],
|
||||
"binaryFolders": [],
|
||||
"deployConfig": {
|
||||
"deployServicePack": true,
|
||||
"deployScripts": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "docsonly",
|
||||
"serverType": "SAS9",
|
||||
"appLoc": "dummy",
|
||||
"macroFolders": [
|
||||
"meta",
|
||||
"metax",
|
||||
"server",
|
||||
"viya",
|
||||
"tests/sas9only",
|
||||
"tests/serveronly",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
Usage:
|
||||
|
||||
%mfs_httpheader(Content-type,application/csv)
|
||||
%mfs_httpheader(Content-Type,application/csv)
|
||||
|
||||
@param [in] header_name Name of the http header to set
|
||||
@param [in] header_value Value of the http header to set
|
||||
@@ -28,6 +28,7 @@
|
||||
%macro mfs_httpheader(header_name
|
||||
,header_value
|
||||
)/*/STORE SOURCE*/;
|
||||
%global sasjs_stpsrv_header_loc;
|
||||
%local fref fid i;
|
||||
|
||||
%if %sysfunc(filename(fref,&sasjs_stpsrv_header_loc)) ne 0 %then %do;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_abort.sas
|
||||
@li ms_deletefile.sas
|
||||
|
||||
**/
|
||||
|
||||
@@ -29,14 +30,22 @@
|
||||
,mdebug=0
|
||||
);
|
||||
|
||||
%local fname0 fname1 boundary fname statcd msg;
|
||||
/* first, delete in case it exists */
|
||||
%ms_deletefile(&driveloc,mdebug=&mdebug)
|
||||
|
||||
%local fname0 fname1 fname2 boundary fname statcd msg optval;
|
||||
%let fname0=%mf_getuniquefileref();
|
||||
%let fname1=%mf_getuniquefileref();
|
||||
%let fname2=%mf_getuniquefileref();
|
||||
%let boundary=%mf_getuniquename();
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
|
||||
data _null_;
|
||||
file &fname0 termstr=crlf;
|
||||
infile &inref end=eof;
|
||||
file &fname0 termstr=crlf lrecl=32767;
|
||||
infile &inref end=eof lrecl=32767;
|
||||
if _n_ = 1 then do;
|
||||
put "--&boundary.";
|
||||
put 'Content-Disposition: form-data; name="filePath"';
|
||||
@@ -55,17 +64,28 @@ data _null_;
|
||||
end;
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
file &fname1 lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put "Content-Type: multipart/form-data; boundary=&boundary";
|
||||
put "Authorization: Bearer " _infile_;
|
||||
run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
data _null_;
|
||||
infile &fname0;
|
||||
infile &fname0 lrecl=32767;
|
||||
input;
|
||||
put _infile_;
|
||||
data _null_;
|
||||
infile &fname1 lrecl=32767;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
proc http method='POST' in=&fname0 out=&fname1
|
||||
proc http method='POST' in=&fname0 headerin=&fname1 out=&fname2
|
||||
url="&_sasjs_apiserverurl/SASjsApi/drive/file";
|
||||
headers "Content-Type"="multipart/form-data; boundary=&boundary";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
@@ -73,7 +93,7 @@ run;
|
||||
|
||||
%let statcd=0;
|
||||
data _null_;
|
||||
infile &fname1;
|
||||
infile &fname2;
|
||||
input;
|
||||
putlog _infile_;
|
||||
if _infile_='{"status":"success"}' then call symputx('statcd',1,'l');
|
||||
@@ -86,4 +106,7 @@ run;
|
||||
,msg=%superq(msg)
|
||||
)
|
||||
|
||||
/* reset options */
|
||||
options &optval;
|
||||
|
||||
%mend ms_createfile;
|
||||
|
||||
144
server/ms_createuser.sas
Normal file
144
server/ms_createuser.sas
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
@file
|
||||
@brief Creates a user on SASjs Server
|
||||
@details Creates a user on SASjs Server with the following attributes:
|
||||
|
||||
@li UserName
|
||||
@li Password
|
||||
@li isAdmin
|
||||
@li displayName
|
||||
|
||||
The userid is created by sasjs/server. All users are created with `isActive`
|
||||
set to `true`.
|
||||
|
||||
Example:
|
||||
|
||||
%ms_createuser(newuser,secretpass,displayname=New User!)
|
||||
|
||||
@param [in] username The username to apply. No spaces or special characters.
|
||||
@param [in] password The initial password to set.
|
||||
@param [in] isadmin= (false) Set to true to give the user admin rights
|
||||
@param [in] displayName= (0) Set a friendly name (spaces & special characters
|
||||
are ok). If not provided, username will be used instead.
|
||||
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
@param [out] outds= (work.ms_createuser) This output dataset will contain the
|
||||
values from the JSON response (such as the id of the new user)
|
||||
|ID:best.|DISPLAYNAME:$8.|USERNAME:$8.|ISACTIVE:best.|ISADMIN:best.|
|
||||
|---|---|---|---|---|
|
||||
|`6 `|`New User `|`newuser `|`1 `|`0 `|
|
||||
|
||||
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_createuser.test.sas
|
||||
@li ms_getusers.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_createuser(username,password
|
||||
,isadmin=false
|
||||
,displayname=0
|
||||
,outds=work.ms_createuser
|
||||
,mdebug=0
|
||||
);
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_createuser.sas
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
|
||||
%local fref0 fref1 fref2 libref optval rc msg;
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let fref2=%mf_getuniquefileref();
|
||||
%let libref=%mf_getuniquelibref();
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
|
||||
data _null_;
|
||||
file &fref0 termstr=crlf;
|
||||
username=quote(cats(symget('username')));
|
||||
password=quote(cats(symget('password')));
|
||||
isadmin=symget('isadmin');
|
||||
displayname=quote(cats(symget('displayname')));
|
||||
if displayname='"0"' then displayname=username;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
putlog _all_;
|
||||
%end;
|
||||
|
||||
put '{'@;
|
||||
put '"displayName":' displayname @;
|
||||
put ',"username":' username @;
|
||||
put ',"password":' password @;
|
||||
put ',"isAdmin":' isadmin @;
|
||||
put ',"isActive": true }';
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
file &fref1 lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put "Authorization: Bearer " _infile_;
|
||||
put "Content-Type: application/json";
|
||||
put "accept: application/json";
|
||||
run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
data _null_;
|
||||
infile &fref0;
|
||||
input;
|
||||
put _infile_;
|
||||
data _null_;
|
||||
infile &fref1;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
proc http method='POST' in=&fref0 headerin=&fref1 out=&fref2
|
||||
url="&_sasjs_apiserverurl/SASjsApi/user";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
run;
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_createuser.sas
|
||||
,msg=%str(Issue submitting query to SASjsApi/user)
|
||||
)
|
||||
|
||||
libname &libref JSON fileref=&fref2;
|
||||
|
||||
data &outds;
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_createuser.sas
|
||||
,msg=%str(Issue reading response JSON)
|
||||
)
|
||||
|
||||
/* reset options */
|
||||
options &optval;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
filename &fref0 clear;
|
||||
filename &fref1 clear;
|
||||
filename &fref2 clear;
|
||||
libname &libref clear;
|
||||
%end;
|
||||
|
||||
%mend ms_createuser;
|
||||
532
server/ms_createwebservice.sas
Normal file
532
server/ms_createwebservice.sas
Normal file
@@ -0,0 +1,532 @@
|
||||
/**
|
||||
@file ms_createwebservice.sas
|
||||
@brief Create a Web-Ready Stored Program
|
||||
@details This macro creates a Stored Program along with the necessary precode
|
||||
to enable the %webout() macro
|
||||
|
||||
Usage:
|
||||
<code>
|
||||
%* compile macros ;
|
||||
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
||||
%inc mc;
|
||||
|
||||
%* parmcards lets us write to a text file from open code ;
|
||||
filename ft15f001 temp;
|
||||
parmcards4;
|
||||
%webout(FETCH)
|
||||
%* do some sas, any inputs are now already WORK tables;
|
||||
data example1 example2;
|
||||
set sashelp.class;
|
||||
run;
|
||||
%* send data back;
|
||||
%webout(OPEN)
|
||||
%webout(ARR,example1) * Array format, fast, suitable for large tables ;
|
||||
%webout(OBJ,example2) * Object format, easier to work with ;
|
||||
%webout(CLOSE)
|
||||
;;;;
|
||||
%ms_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
|
||||
|
||||
</code>
|
||||
|
||||
For more examples of using these web services with the SASjs Adapter, see:
|
||||
https://github.com/sasjs/adapter#readme
|
||||
|
||||
@param [in] path= (0) The full SASjs Drive path in which to create the service
|
||||
@param [in] name= Stored Program name
|
||||
@param [in] desc= The description of the service (not implemented yet)
|
||||
@param [in] precode= Space separated list of filerefs, pointing to the code
|
||||
that needs to be attached to the beginning of the service (optional)
|
||||
@param [in] code= (ft15f001) Space seperated fileref(s) of the actual code to
|
||||
be added
|
||||
@param [in] mDebug= (0) set to 1 to show debug messages in the log
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li ms_createfile.sas
|
||||
@li mf_getuser.sas
|
||||
@li mf_getuniquename.sas
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_createwebservice.test.sas
|
||||
|
||||
@version 9.2
|
||||
@author Allan Bowe
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_createwebservice(path=0
|
||||
,name=initService
|
||||
,precode=
|
||||
,code=ft15f001
|
||||
,desc=Not currently used
|
||||
,mDebug=0
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%local dbg;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname entry vars:;
|
||||
%put _local_;
|
||||
%end;
|
||||
%else %let dbg=*;
|
||||
|
||||
%mp_abort(iftrue=(&syscc ge 4 )
|
||||
,mac=ms_createwebservice
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
%mp_abort(iftrue=("&path"="0")
|
||||
,mac=ms_createwebservice
|
||||
,msg=%str(Path not provided)
|
||||
)
|
||||
|
||||
/* remove any trailing slash */
|
||||
%if "%substr(&path,%length(&path),1)" = "/" %then
|
||||
%let path=%substr(&path,1,%length(&path)-1);
|
||||
|
||||
/**
|
||||
* Add webout macro
|
||||
* These put statements are auto generated - to change the macro, change the
|
||||
* source (ms_webout) and run `build.py`
|
||||
*/
|
||||
%local sasjsref;
|
||||
%let sasjsref=%mf_getuniquefileref();
|
||||
data _null_;
|
||||
file &sasjsref termstr=crlf lrecl=512;
|
||||
put "/* Created on %sysfunc(datetime(),datetime19.) by %mf_getuser() */";
|
||||
/* WEBOUT BEGIN */
|
||||
put ' ';
|
||||
put '%macro mp_jsonout(action,ds,jref=_webout,dslabel=,fmt=Y ';
|
||||
put ' ,engine=DATASTEP ';
|
||||
put ' ,missing=NULL ';
|
||||
put ' ,showmeta=NO ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put '%local tempds colinfo fmtds i numcols; ';
|
||||
put '%let numcols=0; ';
|
||||
put ' ';
|
||||
put '%if &action=OPEN %then %do; ';
|
||||
put ' options nobomfile; ';
|
||||
put ' data _null_;file &jref encoding=''utf-8'' lrecl=200; ';
|
||||
put ' put ''{"PROCESSED_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''"''; ';
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
put '%else %if (&action=ARR or &action=OBJ) %then %do; ';
|
||||
put ' options validvarname=upcase; ';
|
||||
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
||||
put ' put ", ""%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":"; ';
|
||||
put ' ';
|
||||
put ' /* grab col defs */ ';
|
||||
put ' proc contents noprint data=&ds ';
|
||||
put ' out=_data_(keep=name type length format formatl formatd varnum label); ';
|
||||
put ' run; ';
|
||||
put ' %let colinfo=%scan(&syslast,2,.); ';
|
||||
put ' proc sort data=&colinfo; ';
|
||||
put ' by varnum; ';
|
||||
put ' run; ';
|
||||
put ' /* move meta to mac vars */ ';
|
||||
put ' data _null_; ';
|
||||
put ' if _n_=1 then call symputx(''numcols'',nobs,''l''); ';
|
||||
put ' set &colinfo end=last nobs=nobs; ';
|
||||
put ' name=upcase(name); ';
|
||||
put ' /* fix formats */ ';
|
||||
put ' if type=2 or type=6 then do; ';
|
||||
put ' typelong=''char''; ';
|
||||
put ' length fmt $49.; ';
|
||||
put ' if format='''' then fmt=cats(''$'',length,''.''); ';
|
||||
put ' else if formatl=0 then fmt=cats(format,''.''); ';
|
||||
put ' else fmt=cats(format,formatl,''.''); ';
|
||||
put ' newlen=max(formatl,length); ';
|
||||
put ' end; ';
|
||||
put ' else do; ';
|
||||
put ' typelong=''num''; ';
|
||||
put ' if format='''' then fmt=''best.''; ';
|
||||
put ' else if formatl=0 then fmt=cats(format,''.''); ';
|
||||
put ' else if formatd=0 then fmt=cats(format,formatl,''.''); ';
|
||||
put ' else fmt=cats(format,formatl,''.'',formatd); ';
|
||||
put ' /* needs to be wide, for datetimes etc */ ';
|
||||
put ' newlen=max(length,formatl,24); ';
|
||||
put ' end; ';
|
||||
put ' /* 32 char unique name */ ';
|
||||
put ' newname=''sasjs''!!substr(cats(put(md5(name),$hex32.)),1,27); ';
|
||||
put ' ';
|
||||
put ' call symputx(cats(''name'',_n_),name,''l''); ';
|
||||
put ' call symputx(cats(''newname'',_n_),newname,''l''); ';
|
||||
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
|
||||
put ' call symputx(cats(''length'',_n_),length,''l''); ';
|
||||
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
|
||||
put ' call symputx(cats(''type'',_n_),type,''l''); ';
|
||||
put ' call symputx(cats(''typelong'',_n_),typelong,''l''); ';
|
||||
put ' call symputx(cats(''label'',_n_),coalescec(label,name),''l''); ';
|
||||
put ' run; ';
|
||||
put ' ';
|
||||
put ' %let tempds=%substr(_%sysfunc(compress(%sysfunc(uuidgen()),-)),1,32); ';
|
||||
put ' ';
|
||||
put ' %if &engine=PROCJSON %then %do; ';
|
||||
put ' %if &missing=STRING %then %do; ';
|
||||
put ' %put &sysmacroname: Special Missings not supported in proc json.; ';
|
||||
put ' %put &sysmacroname: Switching to DATASTEP engine; ';
|
||||
put ' %goto datastep; ';
|
||||
put ' %end; ';
|
||||
put ' data &tempds;set &ds; ';
|
||||
put ' %if &fmt=N %then format _numeric_ best32.;; ';
|
||||
put ' /* PRETTY is necessary to avoid line truncation in large files */ ';
|
||||
put ' proc json out=&jref pretty ';
|
||||
put ' %if &action=ARR %then nokeys ; ';
|
||||
put ' ;export &tempds / nosastags fmtnumeric; ';
|
||||
put ' run; ';
|
||||
put ' %end; ';
|
||||
put ' %else %if &engine=DATASTEP %then %do; ';
|
||||
put ' %datastep: ';
|
||||
put ' %if %sysfunc(exist(&ds)) ne 1 & %sysfunc(exist(&ds,VIEW)) ne 1 ';
|
||||
put ' %then %do; ';
|
||||
put ' %put &sysmacroname: &ds NOT FOUND!!!; ';
|
||||
put ' %return; ';
|
||||
put ' %end; ';
|
||||
put ' ';
|
||||
put ' %if &fmt=Y %then %do; ';
|
||||
put ' data _data_; ';
|
||||
put ' /* rename on entry */ ';
|
||||
put ' set &ds(rename=( ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' &&name&i=&&newname&i ';
|
||||
put ' %end; ';
|
||||
put ' )); ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' length &&name&i $&&len&i; ';
|
||||
put ' %if &&typelong&i=num %then %do; ';
|
||||
put ' &&name&i=left(put(&&newname&i,&&fmt&i)); ';
|
||||
put ' %end; ';
|
||||
put ' %else %do; ';
|
||||
put ' &&name&i=put(&&newname&i,&&fmt&i); ';
|
||||
put ' %end; ';
|
||||
put ' drop &&newname&i; ';
|
||||
put ' %end; ';
|
||||
put ' if _error_ then call symputx(''syscc'',1012); ';
|
||||
put ' run; ';
|
||||
put ' %let fmtds=&syslast; ';
|
||||
put ' %end; ';
|
||||
put ' ';
|
||||
put ' proc format; /* credit yabwon for special null removal */ ';
|
||||
put ' value bart (default=40) ';
|
||||
put ' %if &missing=NULL %then %do; ';
|
||||
put ' ._ - .z = null ';
|
||||
put ' %end; ';
|
||||
put ' %else %do; ';
|
||||
put ' ._ = [quote()] ';
|
||||
put ' . = null ';
|
||||
put ' .a - .z = [quote()] ';
|
||||
put ' %end; ';
|
||||
put ' other = [best.]; ';
|
||||
put ' ';
|
||||
put ' data &tempds; ';
|
||||
put ' attrib _all_ label=''''; ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||
put ' length &&name&i $32767; ';
|
||||
put ' format &&name&i $32767.; ';
|
||||
put ' %end; ';
|
||||
put ' %end; ';
|
||||
put ' %if &fmt=Y %then %do; ';
|
||||
put ' set &fmtds; ';
|
||||
put ' %end; ';
|
||||
put ' %else %do; ';
|
||||
put ' set &ds; ';
|
||||
put ' %end; ';
|
||||
put ' format _numeric_ bart.; ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; ';
|
||||
put ' &&name&i=''"''!!trim( ';
|
||||
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
|
||||
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
|
||||
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
|
||||
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
|
||||
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
|
||||
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
|
||||
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
|
||||
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
|
||||
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
|
||||
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
|
||||
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
|
||||
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
|
||||
put ' ))))))))))))!!''"''; ';
|
||||
put ' end; ';
|
||||
put ' else &&name&i=quote(cats(&&name&i)); ';
|
||||
put ' %end; ';
|
||||
put ' %end; ';
|
||||
put ' run; ';
|
||||
put ' ';
|
||||
put ' /* write to temp loc to avoid _webout truncation ';
|
||||
put ' - https://support.sas.com/kb/49/325.html */ ';
|
||||
put ' filename _sjs temp lrecl=131068 encoding=''utf-8''; ';
|
||||
put ' data _null_; file _sjs lrecl=131068 encoding=''utf-8'' mod ; ';
|
||||
put ' if _n_=1 then put "["; ';
|
||||
put ' set &tempds; ';
|
||||
put ' if _n_>1 then put "," @; put ';
|
||||
put ' %if &action=ARR %then "[" ; %else "{" ; ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &i>1 %then "," ; ';
|
||||
put ' %if &action=OBJ %then """&&name&i"":" ; ';
|
||||
put ' &&name&i ';
|
||||
put ' %end; ';
|
||||
put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
|
||||
put ' /* now write the long strings to _webout 1 byte at a time */ ';
|
||||
put ' data _null_; ';
|
||||
put ' length filein 8 fileid 8; ';
|
||||
put ' filein=fopen("_sjs",''I'',1,''B''); ';
|
||||
put ' fileid=fopen("&jref",''A'',1,''B''); ';
|
||||
put ' rec=''20''x; ';
|
||||
put ' do while(fread(filein)=0); ';
|
||||
put ' rc=fget(filein,rec,1); ';
|
||||
put ' rc=fput(fileid, rec); ';
|
||||
put ' rc=fwrite(fileid); ';
|
||||
put ' end; ';
|
||||
put ' /* close out the table */ ';
|
||||
put ' rc=fput(fileid, "]"); ';
|
||||
put ' rc=fwrite(fileid); ';
|
||||
put ' rc=fclose(filein); ';
|
||||
put ' rc=fclose(fileid); ';
|
||||
put ' run; ';
|
||||
put ' filename _sjs clear; ';
|
||||
put ' %end; ';
|
||||
put ' ';
|
||||
put ' proc sql; ';
|
||||
put ' drop table &colinfo, &tempds; ';
|
||||
put ' ';
|
||||
put ' %if &showmeta=YES %then %do; ';
|
||||
put ' data _null_; file &jref encoding=''utf-8'' mod; ';
|
||||
put ' put ", ""$%lowcase(%sysfunc(coalescec(&dslabel,&ds)))"":{""vars"":{"; ';
|
||||
put ' do i=1 to &numcols; ';
|
||||
put ' name=quote(trim(symget(cats(''name'',i)))); ';
|
||||
put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
|
||||
put ' label=quote(trim(symget(cats(''label'',i)))); ';
|
||||
put ' length=quote(trim(symget(cats(''length'',i)))); ';
|
||||
put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
|
||||
put ' if i>1 then put "," @@; ';
|
||||
put ' put name '':{"format":'' format '',"label":'' label ';
|
||||
put ' '',"length":'' length '',"type":'' type ''}''; ';
|
||||
put ' end; ';
|
||||
put ' put ''}}''; ';
|
||||
put ' run; ';
|
||||
put ' %end; ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%else %if &action=CLOSE %then %do; ';
|
||||
put ' data _null_; file &jref encoding=''utf-8'' mod ; ';
|
||||
put ' put "}"; ';
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
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 ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
put ' %quote(&user) ';
|
||||
put ' ';
|
||||
put '%mend mf_getuser; ';
|
||||
put ' ';
|
||||
put '%macro ms_webout(action,ds,dslabel=,fref=_webout,fmt=Y,missing=NULL ';
|
||||
put ' ,showmeta=NO ';
|
||||
put '); ';
|
||||
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
|
||||
put ' sasjs_tables; ';
|
||||
put ' ';
|
||||
put '%local i tempds; ';
|
||||
put '%let action=%upcase(&action); ';
|
||||
put ' ';
|
||||
put '%if &action=FETCH %then %do; ';
|
||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
||||
put ' options mprint notes mprintnest; ';
|
||||
put ' %end; ';
|
||||
put ' %let _webin_file_count=%eval(&_webin_file_count+0); ';
|
||||
put ' /* now read in the data */ ';
|
||||
put ' %do i=1 %to &_webin_file_count; ';
|
||||
put ' %if &_webin_file_count=1 %then %do; ';
|
||||
put ' %let _webin_fileref1=&_webin_fileref; ';
|
||||
put ' %let _webin_name1=&_webin_name; ';
|
||||
put ' %end; ';
|
||||
put ' data _null_; ';
|
||||
put ' infile &&_webin_fileref&i termstr=crlf lrecl=32767; ';
|
||||
put ' input; ';
|
||||
put ' call symputx(''input_statement'',_infile_); ';
|
||||
put ' putlog "&&_webin_name&i input statement: " _infile_; ';
|
||||
put ' stop; ';
|
||||
put ' data &&_webin_name&i; ';
|
||||
put ' infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding=''utf-8'' ';
|
||||
put ' lrecl=32767; ';
|
||||
put ' input &input_statement; ';
|
||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
||||
put ' if _n_<20 then putlog _infile_; ';
|
||||
put ' %end; ';
|
||||
put ' run; ';
|
||||
put ' %let sasjs_tables=&sasjs_tables &&_webin_name&i; ';
|
||||
put ' %end; ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%else %if &action=OPEN %then %do; ';
|
||||
put ' /* fix encoding and ensure enough lrecl */ ';
|
||||
put ' OPTIONS NOBOMFILE lrecl=32767; ';
|
||||
put ' ';
|
||||
put ' /* set the header */ ';
|
||||
put ' %mfs_httpheader(Content-type,application/json) ';
|
||||
put ' ';
|
||||
put ' /* setup json. */ ';
|
||||
put ' data _null_;file &fref encoding=''utf-8'' termstr=lf ; ';
|
||||
put ' put ''{"SYSDATE" : "'' "&SYSDATE" ''"''; ';
|
||||
put ' put '',"SYSTIME" : "'' "&SYSTIME" ''"''; ';
|
||||
put ' run; ';
|
||||
put ' ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%else %if &action=ARR or &action=OBJ %then %do; ';
|
||||
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
|
||||
put ' ,engine=DATASTEP,missing=&missing,showmeta=&showmeta ';
|
||||
put ' ) ';
|
||||
put '%end; ';
|
||||
put '%else %if &action=CLOSE %then %do; ';
|
||||
put ' %if %str(&_debug) ge 131 %then %do; ';
|
||||
put ' /* if debug mode, send back first 10 records of each work table also */ ';
|
||||
put ' options obs=10; ';
|
||||
put ' data;run;%let tempds=%scan(&syslast,2,.); ';
|
||||
put ' ods output Members=&tempds; ';
|
||||
put ' proc datasets library=WORK memtype=data; ';
|
||||
put ' %local wtcnt;%let wtcnt=0; ';
|
||||
put ' data _null_; ';
|
||||
put ' set &tempds; ';
|
||||
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
|
||||
put ' if not (upcase(name)=:"_DATA_"); ';
|
||||
put ' i+1; ';
|
||||
put ' call symputx(cats(''wt'',i),name,''l''); ';
|
||||
put ' call symputx(''wtcnt'',i,''l''); ';
|
||||
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
||||
put ' put ",""WORK"":{"; ';
|
||||
put ' %do i=1 %to &wtcnt; ';
|
||||
put ' %let wt=&&wt&i; ';
|
||||
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
||||
put ' dsid=open("WORK.&wt",''is''); ';
|
||||
put ' nlobs=attrn(dsid,''NLOBS''); ';
|
||||
put ' nvars=attrn(dsid,''NVARS''); ';
|
||||
put ' rc=close(dsid); ';
|
||||
put ' if &i>1 then put '',''@; ';
|
||||
put ' put " ""&wt"" : {"; ';
|
||||
put ' put ''"nlobs":'' nlobs; ';
|
||||
put ' put '',"nvars":'' nvars; ';
|
||||
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=YES) ';
|
||||
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
||||
put ' put "}"; ';
|
||||
put ' %end; ';
|
||||
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
|
||||
put ' put "}"; ';
|
||||
put ' run; ';
|
||||
put ' %end; ';
|
||||
put ' /* close off json */ ';
|
||||
put ' data _null_;file &fref mod encoding=''utf-8'' termstr=lf lrecl=32767; ';
|
||||
put ' _PROGRAM=quote(trim(resolve(symget(''_PROGRAM'')))); ';
|
||||
put ' put ",""SYSUSERID"" : ""&sysuserid"" "; ';
|
||||
put ' put ",""MF_GETUSER"" : ""%mf_getuser()"" "; ';
|
||||
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
|
||||
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
|
||||
put ' put ",""SYSCC"" : ""&syscc"" "; ';
|
||||
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
|
||||
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
|
||||
put ' SYSHOSTINFOLONG=quote(trim(symget(''SYSHOSTINFOLONG''))); ';
|
||||
put ' put '',"SYSHOSTINFOLONG" : '' SYSHOSTINFOLONG; ';
|
||||
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
|
||||
put ' put ",""SYSPROCESSID"" : ""&SYSPROCESSID"" "; ';
|
||||
put ' put ",""SYSPROCESSMODE"" : ""&SYSPROCESSMODE"" "; ';
|
||||
put ' length SYSPROCESSNAME $512; ';
|
||||
put ' SYSPROCESSNAME=quote(urlencode(cats(SYSPROCESSNAME))); ';
|
||||
put ' put ",""SYSPROCESSNAME"" : " SYSPROCESSNAME; ';
|
||||
put ' put ",""SYSJOBID"" : ""&sysjobid"" "; ';
|
||||
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
|
||||
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
|
||||
put ' put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" "; ';
|
||||
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
|
||||
put ' put '',"SYSVLONG" : '' sysvlong; ';
|
||||
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
|
||||
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
|
||||
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
|
||||
put ' length autoexec $512; ';
|
||||
put ' autoexec=quote(urlencode(trim(getoption(''autoexec'')))); ';
|
||||
put ' put '',"AUTOEXEC" : '' autoexec; ';
|
||||
put ' length memsize $32; ';
|
||||
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
|
||||
put ' memsize=quote(cats(memsize)); ';
|
||||
put ' put '',"MEMSIZE" : '' memsize; ';
|
||||
put ' put "}" @; ';
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%mend ms_webout; ';
|
||||
put ' ';
|
||||
put '%macro mfs_httpheader(header_name ';
|
||||
put ' ,header_value ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put '%global sasjs_stpsrv_header_loc; ';
|
||||
put '%local fref fid i; ';
|
||||
put ' ';
|
||||
put '%if %sysfunc(filename(fref,&sasjs_stpsrv_header_loc)) ne 0 %then %do; ';
|
||||
put ' %put &=fref &=sasjs_stpsrv_header_loc; ';
|
||||
put ' %put %str(ERR)OR: %sysfunc(sysmsg()); ';
|
||||
put ' %return; ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%let fid=%sysfunc(fopen(&fref,A)); ';
|
||||
put ' ';
|
||||
put '%if &fid=0 %then %do; ';
|
||||
put ' %put %str(ERR)OR: %sysfunc(sysmsg()); ';
|
||||
put ' %return; ';
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%let rc=%sysfunc(fput(&fid,%str(&header_name): %str(&header_value))); ';
|
||||
put '%let rc=%sysfunc(fwrite(&fid)); ';
|
||||
put ' ';
|
||||
put '%let rc=%sysfunc(fclose(&fid)); ';
|
||||
put '%let rc=%sysfunc(filename(&fref)); ';
|
||||
put ' ';
|
||||
put '%mend mfs_httpheader; ';
|
||||
/* WEBOUT END */
|
||||
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
|
||||
put ' %ms_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
|
||||
put ' ,showmeta=&showmeta';
|
||||
put ' )';
|
||||
put '%mend;';
|
||||
run;
|
||||
|
||||
/* add precode and code */
|
||||
%local x fref freflist;
|
||||
%let freflist=&precode &code ;
|
||||
%do x=1 %to %sysfunc(countw(&freflist));
|
||||
%let fref=%scan(&freflist,&x);
|
||||
%put &sysmacroname: adding &fref;
|
||||
data _null_;
|
||||
file &sasjsref lrecl=3000 termstr=crlf mod;
|
||||
infile &fref lrecl=3000;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
/* create the web service */
|
||||
%ms_createfile(&path/&name..sas, inref=&sasjsref, mdebug=&mdebug)
|
||||
|
||||
%put ;%put ;%put ;%put ;%put ;%put ;
|
||||
%put &sysmacroname: STP &name successfully created in &path;
|
||||
%put ;%put ;%put ;
|
||||
%put Check it out here:;
|
||||
%put ;%put ;%put ;
|
||||
%put &_sasjs_apiserverurl.&_sasjs_apipath?_PROGRAM=&path/&name;
|
||||
%put ;%put ;%put ;%put ;%put ;%put ;
|
||||
|
||||
%mend ms_createwebservice;
|
||||
48
server/ms_deletefile.sas
Normal file
48
server/ms_deletefile.sas
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
@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
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_deletefile(driveloc
|
||||
,mdebug=0
|
||||
);
|
||||
|
||||
%local headref;
|
||||
%let headref=%mf_getuniquefileref();
|
||||
|
||||
data _null_;
|
||||
file &headref lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put "Authorization: Bearer " _infile_;
|
||||
run;
|
||||
|
||||
proc http method='DELETE' headerin=&headref
|
||||
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=2;
|
||||
%end;
|
||||
run;
|
||||
|
||||
filename &headref clear;
|
||||
|
||||
%mend ms_deletefile;
|
||||
50
server/ms_getfile.sas
Normal file
50
server/ms_getfile.sas
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
@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(/Public/app/dc/services/public/settings.sas, 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 headref;
|
||||
%let binaryfref=%mf_getuniquefileref();
|
||||
%let headref=%mf_getuniquefileref();
|
||||
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
|
||||
filename &outref "&floc" lrecl=32767;
|
||||
filename &binaryfref "&floc" recfm=n;
|
||||
|
||||
data _null_;
|
||||
file &headref lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put "Authorization: Bearer " _infile_;
|
||||
run;
|
||||
|
||||
proc http method='GET' out=&binaryfref headerin=&headref
|
||||
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=2;
|
||||
%end;
|
||||
run;
|
||||
|
||||
filename &binaryfref clear;
|
||||
filename &headref clear;
|
||||
|
||||
%mend ms_getfile;
|
||||
107
server/ms_getusers.sas
Normal file
107
server/ms_getusers.sas
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
@file
|
||||
@brief Fetches the list of users from SASjs Server
|
||||
@details Fetches the list of users from SASjs Server and writes them to an
|
||||
output dataset.
|
||||
|
||||
Example:
|
||||
|
||||
%ms_getusers(outds=userlist)
|
||||
|
||||
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
@param [out] outds= (work.ms_getusers) This output dataset will contain the
|
||||
list of user accounts. Format:
|
||||
|DISPLAYNAME:$18.|USERNAME:$10.|ID:best.|
|
||||
|---|---|---|
|
||||
|`Super Admin `|`secretuser `|`1`|
|
||||
|`Sabir Hassan`|`sabir`|`2`|
|
||||
|`Mihajlo Medjedovic `|`mihajlo `|`3`|
|
||||
|`Ivor Townsend `|`ivor `|`4`|
|
||||
|`New User `|`newuser `|`5`|
|
||||
|
||||
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_createuser.sas
|
||||
@li ms_getusers.test.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_getusers(
|
||||
outds=work.ms_getusers
|
||||
,mdebug=0
|
||||
);
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
|
||||
%local fref0 fref1 libref optval rc msg;
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let libref=%mf_getuniquelibref();
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
|
||||
data _null_;
|
||||
file &fref0 lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put "Authorization: Bearer " _infile_;
|
||||
put "accept: application/json";
|
||||
run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
data _null_;
|
||||
infile &fref0;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
proc http method='GET' headerin=&fref0 out=&fref1
|
||||
url="&_sasjs_apiserverurl/SASjsApi/user";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
run;
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,msg=%str(Issue submitting GET query to SASjsApi/user)
|
||||
)
|
||||
|
||||
libname &libref JSON fileref=&fref1;
|
||||
|
||||
data &outds;
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,msg=%str(Issue reading response JSON)
|
||||
)
|
||||
|
||||
/* reset options */
|
||||
options &optval;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
filename &fref0 clear;
|
||||
filename &fref1 clear;
|
||||
libname &libref clear;
|
||||
%end;
|
||||
|
||||
%mend ms_getusers;
|
||||
@@ -15,48 +15,154 @@
|
||||
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 [in] inputparams=(_null_) A dataset containing name/value pairs in the
|
||||
following format:
|
||||
|name:$32|value:$10000|
|
||||
|---|---|
|
||||
|stpmacname|some value|
|
||||
|mustbevalidname|can be anything, oops, %abort!!|
|
||||
@param [in] inputfiles= (_null_) A dataset containing fileref/name/filename in
|
||||
the following format:
|
||||
|fileref:$8|name:$32|filename:$256|
|
||||
|---|---|--|
|
||||
|someref|some_name|some_filename.xls|
|
||||
|fref2|another_file|zyx_v2.csv|
|
||||
|
||||
@param [out] outref= (outweb) The output fileref to contain the response JSON
|
||||
(will be created using temp engine)
|
||||
@param [out] outlogds= (_null_) Set to the name of a dataset to contain the
|
||||
log. Table format:
|
||||
|line:$2000|
|
||||
|---|
|
||||
|log line 1|
|
||||
|log line 2|
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_runstp(pgm
|
||||
,debug=131
|
||||
,inputparams=_null_
|
||||
,inputfiles=_null_
|
||||
,outref=outweb
|
||||
,outlogds=_null_
|
||||
,mdebug=0
|
||||
);
|
||||
%local dbg fname1;
|
||||
%local dbg mainref authref boundary;
|
||||
%let mainref=%mf_getuniquefileref();
|
||||
%let authref=%mf_getuniquefileref();
|
||||
%let boundary=%mf_getuniquename();
|
||||
%if &inputparams=0 %then %let inputparams=_null_;
|
||||
|
||||
%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)
|
||||
)
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%local optval;
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
|
||||
/* add params */
|
||||
data _null_;
|
||||
file &fname1;
|
||||
infile "&_sasjs_tokenfile";
|
||||
input;
|
||||
put 'Authorization: Bearer' _infile_;
|
||||
file &mainref termstr=crlf lrecl=32767 mod;
|
||||
length line $1000 name $32 value $32767;
|
||||
if _n_=1 then call missing(of _all_);
|
||||
set &inputparams;
|
||||
put "--&boundary";
|
||||
line=cats('Content-Disposition: form-data; name="',name,'"');
|
||||
put line;
|
||||
put ;
|
||||
put value;
|
||||
run;
|
||||
|
||||
filename &outref temp;
|
||||
/* parse input file list */
|
||||
%local webcount;
|
||||
%let webcount=0;
|
||||
data _null_;
|
||||
set &inputfiles end=last;
|
||||
length fileref $8 name $32 filename $256;
|
||||
call symputx(cats('webref',_n_),fileref,'l');
|
||||
call symputx(cats('webname',_n_),name,'l');
|
||||
call symputx(cats('webfilename',_n_),filename,'l');
|
||||
if last then do;
|
||||
call symputx('webcount',_n_);
|
||||
call missing(of _all_);
|
||||
end;
|
||||
run;
|
||||
|
||||
/* write out the input files */
|
||||
%local i;
|
||||
%do i=1 %to &webcount;
|
||||
data _null_;
|
||||
file &mainref termstr=crlf lrecl=32767 mod;
|
||||
infile &&webref&i lrecl=32767;
|
||||
if _n_ = 1 then do;
|
||||
length line $32767;
|
||||
line=cats(
|
||||
'Content-Disposition: form-data; name="'
|
||||
,"&&webname&i"
|
||||
,'"; filename="'
|
||||
,"&&webfilename&i"
|
||||
,'"'
|
||||
);
|
||||
put "--&boundary";
|
||||
put line;
|
||||
put "Content-Type: text/plain";
|
||||
put ;
|
||||
end;
|
||||
input;
|
||||
put _infile_; /* add the actual file to be sent */
|
||||
run;
|
||||
%end;
|
||||
|
||||
data _null_;
|
||||
file &mainref termstr=crlf mod;
|
||||
put "--&boundary--";
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
file &authref lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
put 'Authorization: Bearer ' _infile_;
|
||||
put "Content-Type: multipart/form-data; boundary=&boundary";
|
||||
run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
data _null_;
|
||||
infile &authref;
|
||||
input;
|
||||
put _infile_;
|
||||
data _null_;
|
||||
infile &mainref;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
filename &outref temp lrecl=32767;
|
||||
/* prepare request*/
|
||||
proc http method='POST' headerin=&fname1 out=&outref
|
||||
proc http method='POST' headerin=&authref in=&mainref out=&outref
|
||||
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=2;
|
||||
%end;
|
||||
run;
|
||||
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||
or &mdebug=1 %then %do;
|
||||
%then %do;
|
||||
data _null_;infile &outref;input;putlog _infile_;run;
|
||||
%end;
|
||||
%mp_abort(
|
||||
@@ -65,6 +171,20 @@ run;
|
||||
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||
)
|
||||
|
||||
/* reset options */
|
||||
options &optval;
|
||||
|
||||
%if &outlogds ne _null_ or &mdebug=1 %then %do;
|
||||
%local dumplib;
|
||||
%let dumplib=%mf_getuniquelibref();
|
||||
libname &dumplib json (&outref);
|
||||
data &outlogds;
|
||||
set &dumplib..log;
|
||||
%if &mdebug=1 %then %do;
|
||||
putlog line=;
|
||||
%end;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname exit vars:;
|
||||
@@ -72,6 +192,7 @@ run;
|
||||
%end;
|
||||
%else %do;
|
||||
/* clear refs */
|
||||
filename &fname1 clear;
|
||||
filename &authref;
|
||||
filename &mainref;
|
||||
%end;
|
||||
%mend ms_runstp;
|
||||
154
server/ms_testservice.sas
Normal file
154
server/ms_testservice.sas
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
@file
|
||||
@brief Will execute a SASjs web service on SASjs Server
|
||||
@details Prepares the input files and retrieves the resulting datasets from
|
||||
the response JSON.
|
||||
|
||||
@param [in] program The Stored Program endpoint to test
|
||||
@param [in] inputfiles=(0) A list of space seperated fileref:filename pairs as
|
||||
follows:
|
||||
inputfiles=inref:filename inref2:filename2
|
||||
@param [in] inputdatasets= (0) All datasets in this space seperated list are
|
||||
converted into SASJS-formatted CSVs (see mp_ds2csv.sas) files and added to
|
||||
the list of `inputfiles` for ingestion. The dataset will be sent with the
|
||||
same name (no need for a colon modifier).
|
||||
@param [in] inputparams=(0) A dataset containing name/value pairs in the
|
||||
following format:
|
||||
|name:$32|value:$1000|
|
||||
|---|---|
|
||||
|stpmacname|some value|
|
||||
|mustbevalidname|can be anything, oops, %abort!!|
|
||||
|
||||
@param [in] debug= (131) Provide the _debug value to pass to the STP
|
||||
@param [in] mdebug= (0) Set to 1 to provide macro debugging (this macro)
|
||||
@param [out] outlib= (0) Output libref to contain the final tables. Set to
|
||||
0 if the service output is not in JSON format.
|
||||
@param [out] outref= (0) Output fileref to create, to contain the full _webout
|
||||
response.
|
||||
@param [out] outlogds= (_null_) Set to the name of a dataset to contain the
|
||||
log. Table format:
|
||||
|line:$2000|
|
||||
|---|
|
||||
|log line 1|
|
||||
|log line 2|
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_abort.sas
|
||||
@li mp_binarycopy.sas
|
||||
@li mp_chop.sas
|
||||
@li mp_ds2csv.sas
|
||||
@li ms_runstp.sas
|
||||
|
||||
<h4> Related Programs </h4>
|
||||
@li mp_testservice.test.sas
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_testservice(program,
|
||||
inputfiles=0,
|
||||
inputdatasets=0,
|
||||
inputparams=0,
|
||||
debug=0,
|
||||
mdebug=0,
|
||||
outlib=0,
|
||||
outref=0,
|
||||
outlogds=_null_
|
||||
)/*/STORE SOURCE*/;
|
||||
%local dbg i var ds1 fref1 chopout1 chopout2;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname entry vars:;
|
||||
%put _local_;
|
||||
%end;
|
||||
%else %let dbg=*;
|
||||
|
||||
/* convert inputdatasets to filerefs */
|
||||
%if "&inputdatasets" ne "0" %then %do;
|
||||
%if %quote(&inputfiles)=0 %then %let inputfiles=;
|
||||
%do i=1 %to %sysfunc(countw(&inputdatasets,%str( )));
|
||||
%let var=%scan(&inputdatasets,&i,%str( ));
|
||||
%local dsref&i;
|
||||
%let dsref&i=%mf_getuniquefileref();
|
||||
%mp_ds2csv(&var,outref=&&dsref&i,headerformat=SASJS)
|
||||
%let inputfiles=&inputfiles &&dsref&i:%scan(&var,-1,.);
|
||||
%end;
|
||||
%end;
|
||||
|
||||
/* parse the filerefs - convert to a dataset */
|
||||
%let ds1=%mf_getuniquename();
|
||||
data &ds1;
|
||||
length fileref $8 name $32 filename $256 var $300;
|
||||
if "&inputfiles" ne "0" then do;
|
||||
webcount=countw("&inputfiles");
|
||||
do i=1 to webcount;
|
||||
var=scan("&inputfiles",i,' ');
|
||||
fileref=scan(var,1,':');
|
||||
name=scan(var,2,':');
|
||||
filename=cats(name,'.csv');
|
||||
output;
|
||||
end;
|
||||
end;
|
||||
run;
|
||||
|
||||
|
||||
/* execute the STP */
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
|
||||
%ms_runstp(&program
|
||||
,debug=&debug
|
||||
,inputparams=&inputparams
|
||||
,inputfiles=&ds1
|
||||
,outref=&fref1
|
||||
,mdebug=&mdebug
|
||||
,outlogds=&outlogds
|
||||
)
|
||||
|
||||
|
||||
/* SASjs services have the _webout embedded in wrapper JSON */
|
||||
/* Files can also be very large - so use a dedicated macro to chop it out */
|
||||
%local matchstr1 matchstr2 ;
|
||||
%let matchstr1={"status":"success","_webout":{;
|
||||
%let matchstr2=},"log":[{;
|
||||
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
|
||||
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
|
||||
|
||||
%mp_chop("%sysfunc(pathname(&fref1,F))"
|
||||
,matchvar=matchstr1
|
||||
,keep=LAST
|
||||
,matchpoint=END
|
||||
,offset=-1
|
||||
,outfile="&chopout1"
|
||||
,mdebug=&mdebug
|
||||
)
|
||||
|
||||
%mp_chop("&chopout1"
|
||||
,matchvar=matchstr2
|
||||
,keep=FIRST
|
||||
,matchpoint=START
|
||||
,offset=1
|
||||
,outfile="&chopout2"
|
||||
,mdebug=&mdebug
|
||||
)
|
||||
|
||||
%if &outlib ne 0 %then %do;
|
||||
libname &outlib json "&chopout2";
|
||||
%end;
|
||||
%if &outref ne 0 %then %do;
|
||||
filename &outref "&chopout2";
|
||||
%end;
|
||||
|
||||
%if &mdebug=0 %then %do;
|
||||
filename &webref clear;
|
||||
filename &fref1 clear;
|
||||
filename &fref2 clear;
|
||||
%end;
|
||||
%else %do;
|
||||
%put &sysmacroname exit vars:;
|
||||
%put _local_;
|
||||
%end;
|
||||
|
||||
%mend ms_testservice;
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
@file
|
||||
@brief Send data to/from @sasjs/server
|
||||
@brief Send data to/from sasjs/server
|
||||
@details This macro should be added to the start of each web service,
|
||||
**immediately** followed by a call to:
|
||||
|
||||
@@ -67,13 +67,14 @@
|
||||
%let _webin_name1=&_webin_name;
|
||||
%end;
|
||||
data _null_;
|
||||
infile &&_webin_fileref&i termstr=crlf;
|
||||
infile &&_webin_fileref&i termstr=crlf lrecl=32767;
|
||||
input;
|
||||
call symputx('input_statement',_infile_);
|
||||
putlog "&&_webin_name&i input statement: " _infile_;
|
||||
stop;
|
||||
data &&_webin_name&i;
|
||||
infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding='utf-8';
|
||||
infile &&_webin_fileref&i firstobs=2 dsd termstr=crlf encoding='utf-8'
|
||||
lrecl=32767;
|
||||
input &input_statement;
|
||||
%if %str(&_debug) ge 131 %then %do;
|
||||
if _n_<20 then putlog _infile_;
|
||||
@@ -84,14 +85,14 @@
|
||||
%end;
|
||||
|
||||
%else %if &action=OPEN %then %do;
|
||||
/* fix encoding */
|
||||
OPTIONS NOBOMFILE;
|
||||
/* fix encoding and ensure enough lrecl */
|
||||
OPTIONS NOBOMFILE lrecl=32767;
|
||||
|
||||
/* set the header */
|
||||
%mfs_httpheader(Content-type,application/json)
|
||||
|
||||
/* setup json */
|
||||
data _null_;file &fref encoding='utf-8' termstr=lf;
|
||||
/* setup json. */
|
||||
data _null_;file &fref encoding='utf-8' termstr=lf ;
|
||||
put '{"SYSDATE" : "' "&SYSDATE" '"';
|
||||
put ',"SYSTIME" : "' "&SYSTIME" '"';
|
||||
run;
|
||||
@@ -114,6 +115,7 @@
|
||||
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');
|
||||
@@ -134,19 +136,20 @@
|
||||
data _null_; file &fref mod encoding='utf-8' termstr=lf;
|
||||
put "}";
|
||||
%end;
|
||||
data _null_; file &fref mod encoding='utf-8' termstr=lf termstr=lf;
|
||||
data _null_; file &fref mod encoding='utf-8' termstr=lf;
|
||||
put "}";
|
||||
run;
|
||||
%end;
|
||||
/* close off json */
|
||||
data _null_;file &fref mod encoding='utf-8' termstr=lf;
|
||||
data _null_;file &fref mod encoding='utf-8' termstr=lf lrecl=32767;
|
||||
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
|
||||
put ",""SYSUSERID"" : ""&sysuserid"" ";
|
||||
put ",""MF_GETUSER"" : ""%mf_getuser()"" ";
|
||||
put ",""_DEBUG"" : ""&_debug"" ";
|
||||
put ',"_PROGRAM" : ' _PROGRAM ;
|
||||
put ",""SYSCC"" : ""&syscc"" ";
|
||||
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
|
||||
syserrortext=quote(cats(symget('SYSERRORTEXT')));
|
||||
put ',"SYSERRORTEXT" : ' syserrortext;
|
||||
SYSHOSTINFOLONG=quote(trim(symget('SYSHOSTINFOLONG')));
|
||||
put ',"SYSHOSTINFOLONG" : ' SYSHOSTINFOLONG;
|
||||
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
|
||||
@@ -161,7 +164,8 @@
|
||||
put ",""SYSTCPIPHOSTNAME"" : ""&SYSTCPIPHOSTNAME"" ";
|
||||
sysvlong=quote(trim(symget('sysvlong')));
|
||||
put ',"SYSVLONG" : ' sysvlong;
|
||||
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
|
||||
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
|
||||
put ',"SYSWARNINGTEXT" : ' syswarningtext;
|
||||
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
|
||||
length autoexec $512;
|
||||
autoexec=quote(urlencode(trim(getoption('autoexec'))));
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
29
tests/crossplatform/mf_deletefile.test.sas
Normal file
29
tests/crossplatform/mf_deletefile.test.sas
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
@@ -30,4 +30,12 @@
|
||||
),
|
||||
desc=Checking mf_isint(-1),
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(
|
||||
"%mf_isint()"="0"
|
||||
),
|
||||
desc=Checking mf_isint(),
|
||||
outds=work.test_results
|
||||
)
|
||||
@@ -41,7 +41,7 @@ run;
|
||||
|
||||
/* multibyte string check */
|
||||
|
||||
filename tmp2 temp;
|
||||
filename tmp2 temp lrecl=500;
|
||||
data _null_;
|
||||
file tmp2;
|
||||
put "'╤', '╔', '╗', '═', '╧', '╚', '╝', '║', '╟', '─', '┼', '║', '╢', '│'";
|
||||
|
||||
70
tests/crossplatform/mp_chop.test.sas
Normal file
70
tests/crossplatform/mp_chop.test.sas
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing mp_chop.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_chop.sas
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
|
||||
**/
|
||||
|
||||
/* prep input string */
|
||||
%let src="%sysfunc(pathname(work))/file.txt";
|
||||
%let str=Chop here!;
|
||||
%let out1="%sysfunc(pathname(work))/file1.txt";
|
||||
%let out2="%sysfunc(pathname(work))/file2.txt";
|
||||
%let out3="%sysfunc(pathname(work))/file3.txt";
|
||||
%let out4="%sysfunc(pathname(work))/file4.txt";
|
||||
|
||||
data _null_;
|
||||
file &src;
|
||||
put "startsection&str.endsection";
|
||||
run;
|
||||
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%mp_chop(&src, matchvar=str, keep=FIRST, outfile=&out1)
|
||||
%mp_chop(&src, matchvar=str, keep=LAST, outfile=&out2)
|
||||
%mp_chop(&src, matchvar=str, keep=FIRST, matchpoint=END, outfile=&out3)
|
||||
%mp_chop(&src, matchvar=str, keep=LAST, matchpoint=END, outfile=&out4)
|
||||
%mp_assertscope(COMPARE)
|
||||
|
||||
data _null_;
|
||||
infile &out1 lrecl=200;
|
||||
input;
|
||||
call symputx('test1',_infile_);
|
||||
data _null_;
|
||||
infile &out2 lrecl=200;
|
||||
input;
|
||||
call symputx('test2',_infile_);
|
||||
data _null_;
|
||||
infile &out3 lrecl=200;
|
||||
input;
|
||||
call symputx('test3',_infile_);
|
||||
data _null_;
|
||||
infile &out4 lrecl=200;
|
||||
input;
|
||||
call symputx('test4',_infile_);
|
||||
run;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=("&test1" = "startsection"),
|
||||
desc=Checking keep FIRST matchpoint START
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=("&test2" = "Chop here!endsection"),
|
||||
desc=Checking keep LAST matchpoint START
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=("&test3" = "startsectionChop here!"),
|
||||
desc=Checking keep FIRST matchpoint END
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=("&test4" = "endsection"),
|
||||
desc=Checking keep LAST matchpoint END
|
||||
outds=work.test_results
|
||||
)
|
||||
28
tests/crossplatform/mp_createwebservice.test.sas
Normal file
28
tests/crossplatform/mp_createwebservice.test.sas
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_createwebservice.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mp_assertscope.sas
|
||||
@li mp_createwebservice.sas
|
||||
|
||||
**/
|
||||
|
||||
%let path=&mcTestAppLoc/mp_createwebservice;
|
||||
%let name=myservice;
|
||||
%let fref=%mf_getuniquefileref();
|
||||
|
||||
data _null_;
|
||||
file &fref lrecl=3000;
|
||||
put '%put hello world;';
|
||||
run;
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%mp_createwebservice(path=&path,name=&name,code=&fref,mdebug=&sasjs_mdebug)
|
||||
%mp_assertscope(COMPARE)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,4 +47,18 @@ 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
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
, cards_file= "%sysfunc(pathname(work))/cars.sas"
|
||||
, showlog=NO
|
||||
)
|
||||
%inc "%sysfunc(pathname(work))/cars.sas"/source2;
|
||||
%inc "%sysfunc(pathname(work))/cars.sas"/source2 lrecl=32767;
|
||||
|
||||
proc compare base=sashelp.cars compare=work.test;
|
||||
quit;
|
||||
@@ -48,7 +48,7 @@ run;
|
||||
, append=
|
||||
)
|
||||
|
||||
%inc "%sysfunc(pathname(work))/c2.sas"/source2;
|
||||
%inc "%sysfunc(pathname(work))/c2.sas"/source2 lrecl=32767;
|
||||
|
||||
proc compare base=work.binarybase compare=work.binarycompare;
|
||||
run;
|
||||
|
||||
@@ -88,4 +88,50 @@ run;
|
||||
/* constraint capture at library level is functional - uses first 2 tests */
|
||||
%mp_getpk(work,outds=test4)
|
||||
|
||||
%mp_assertdsobs(work.test4,test=ATLEAST 2)
|
||||
%mp_assertdsobs(work.test4,test=ATLEAST 2)
|
||||
|
||||
/* unique & not null INDEX captured */
|
||||
proc sql;
|
||||
create table work.example5(
|
||||
TX_FROM float format=datetime19.,
|
||||
DD_TYPE char(16),
|
||||
DD_SOURCE char(2048),
|
||||
DD_SHORTDESC char(256)
|
||||
);
|
||||
proc datasets lib=work noprint;
|
||||
modify example5;
|
||||
index create tx_from /nomiss unique;
|
||||
quit;
|
||||
%mp_getpk(work,ds=example5,outds=test5)
|
||||
data _null_;
|
||||
set work.test5;
|
||||
call symputx('test5',pk_fields);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=("&test5"="TX_FROM"),
|
||||
desc=mp_getpk captures single column not null unique index,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/* unique & not null COMPOSITE INDEX captured */
|
||||
proc sql;
|
||||
create table work.example6(
|
||||
TX_FROM float format=datetime19.,
|
||||
DD_TYPE char(16),
|
||||
DD_SOURCE char(2048),
|
||||
DD_SHORTDESC char(256)
|
||||
);
|
||||
proc datasets lib=work noprint;
|
||||
modify example6;
|
||||
index create pk_6=(tx_from dd_type) /nomiss unique;
|
||||
quit;
|
||||
%mp_getpk(work,ds=example6,outds=test6)
|
||||
data _null_;
|
||||
set work.test6;
|
||||
call symputx('test6',pk_fields);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=("&test6"="TX_FROM DD_TYPE"),
|
||||
desc=mp_getpk captures multiple column not null unique index,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
|
||||
**/
|
||||
|
||||
|
||||
%macro gsubtest();
|
||||
%if "%substr(&sysver.XX,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
|
||||
*/
|
||||
@@ -63,4 +70,8 @@ run;
|
||||
iftrue=("&strcheck2b"="&str2"),
|
||||
desc=Check that multi line replacement was successful (line3),
|
||||
outds=work.test_results
|
||||
)
|
||||
)
|
||||
|
||||
%mend gsubtest;
|
||||
|
||||
%gsubtest()
|
||||
|
||||
61
tests/crossplatform/mp_hashdataset.test.sas
Normal file
61
tests/crossplatform/mp_hashdataset.test.sas
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
53
tests/crossplatform/mp_jsonout.test.3.sas
Normal file
53
tests/crossplatform/mp_jsonout.test.3.sas
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing mp_jsonout.sas macro with non-standard chars
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_jsonout.sas
|
||||
@li mp_assert.sas
|
||||
|
||||
**/
|
||||
|
||||
filename webref temp;
|
||||
|
||||
data demo;
|
||||
do x='"','0A'x,'0D'x,'09'x,'00'x,'0E'x,'0F'x,'01'x,'02'x,'10'x,'11'x,'\';
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
%mp_jsonout(OPEN,jref=webref)
|
||||
%mp_jsonout(OBJ,demo,jref=webref)
|
||||
%mp_jsonout(CLOSE,jref=webref)
|
||||
|
||||
data _null_;
|
||||
infile webref;
|
||||
input;
|
||||
putlog _infile_;
|
||||
run;
|
||||
|
||||
libname web JSON fileref=webref;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&syscc=0),
|
||||
desc=Checking for error condition with special chars export,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/*
|
||||
data _null_;
|
||||
set work.demo (in=start) web.demo (in=end);
|
||||
put (_all_)(=);
|
||||
run;
|
||||
proc sql;
|
||||
describe table work.demo;
|
||||
describe table web.demo;
|
||||
*/
|
||||
|
||||
proc compare base=work.demo compare=web.demo(keep=x);
|
||||
quit;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&sysinfo=0),
|
||||
desc=Returned json is identical to input table for all special chars,
|
||||
outds=work.test_results
|
||||
)
|
||||
@@ -3,6 +3,7 @@
|
||||
@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
|
||||
@@ -12,6 +13,8 @@
|
||||
/* prep format catalog */
|
||||
libname perm (work);
|
||||
|
||||
%mddl_dc_difftable(libds=perm.audit)
|
||||
|
||||
data work.loadfmts;
|
||||
length fmtname $32;
|
||||
eexcl='Y';
|
||||
@@ -49,7 +52,7 @@ run;
|
||||
%mp_loadformat(perm.testcat
|
||||
,work.stagedata
|
||||
,loadtarget=YES
|
||||
,auditlibds=0
|
||||
,auditlibds=perm.audit
|
||||
,locklibds=0
|
||||
,delete_col=deleteme
|
||||
,outds_add=add_test1
|
||||
@@ -73,4 +76,18 @@ 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
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ run;
|
||||
%let str=%str(replacewith trailing spaces );
|
||||
%let rep=%str( with more spaces );
|
||||
data _null_;
|
||||
file &test2;
|
||||
file &test2 lrecl=500;
|
||||
put 'blahblah';
|
||||
put "blahblah&str.blah&str. replace &str.X";
|
||||
put "blahbreplacewith&str.spacesahblah";
|
||||
@@ -47,7 +47,7 @@ run;
|
||||
%mp_replace(&test2, findvar=str, replacevar=rep)
|
||||
|
||||
data _null_;
|
||||
infile &test2;
|
||||
infile &test2 lrecl=500;
|
||||
input;
|
||||
if _n_=2 then call symputx('test2resulta',_infile_);
|
||||
if _n_=3 then call symputx('test2resultb',_infile_);
|
||||
@@ -63,3 +63,33 @@ run;
|
||||
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 lrecl=500;
|
||||
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 lrecl=500;
|
||||
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
|
||||
)
|
||||
|
||||
@@ -55,37 +55,28 @@ run;
|
||||
outlib=testlib1,
|
||||
outref=test1
|
||||
)
|
||||
|
||||
%global test1a test1b test1c test1d;
|
||||
%let test1=FAIL;
|
||||
data _null_;
|
||||
infile test1;
|
||||
input;
|
||||
putlog _n_ _infile_;
|
||||
if _infile_=', "somedata1":' then call symputx('test1a','PASS');
|
||||
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
||||
call symputx('test1b','PASS');
|
||||
if _infile_='], "somedata2":' then call symputx('test1c','PASS');
|
||||
if _infile_='{"X":1 ,"Y":" t\"w\"o" ,"Z":"Z" }' then
|
||||
call symputx('test1d','PASS');
|
||||
set testlib1.somedata1;
|
||||
if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
|
||||
%let test2=FAIL;
|
||||
data _null_;
|
||||
set testlib1.somedata2;
|
||||
if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&test1a=PASS),
|
||||
desc=Test 1 table 1 name,
|
||||
iftrue=(&test1=PASS),
|
||||
desc=somedata1 created correctly,
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=(&test1b=PASS),
|
||||
desc=Test 1 table 1 values,
|
||||
iftrue=(&test2=PASS),
|
||||
desc=somedata2 created correctly,
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=(&test1c=PASS),
|
||||
desc=Test 1 table 2 name,
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=(&test1d=PASS),
|
||||
desc=Test 1 table 2 values,
|
||||
outds=work.test_results
|
||||
)
|
||||
41
tests/sas9only/mm_spkexport.test.sas
Normal file
41
tests/sas9only/mm_spkexport.test.sas
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
@@ -9,11 +9,12 @@
|
||||
|
||||
**/
|
||||
|
||||
%let orig_sasjs_stpsrv_header_loc=&sasjs_stpsrv_header_loc;
|
||||
%let sasjs_stpsrv_header_loc=%sysfunc(pathname(work))/header.txt;
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%mfs_httpheader(Content-type,application/csv)
|
||||
%mp_assertscope(COMPARE)
|
||||
%mfs_httpheader(Content-Type,application/csv)
|
||||
%mp_assertscope(COMPARE,ignorelist=sasjs_stpsrv_header_loc)
|
||||
|
||||
data _null_;
|
||||
infile "&sasjs_stpsrv_header_loc";
|
||||
@@ -27,12 +28,12 @@ run;
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=("&test1"="Content-type: application/csv"),
|
||||
iftrue=("&test1"="Content-Type: application/csv"),
|
||||
desc=Checking line was created,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
%mfs_httpheader(Content-type,application/text)
|
||||
%mfs_httpheader(Content-Type,application/text)
|
||||
%let test2=0;
|
||||
data _null_;
|
||||
infile "&sasjs_stpsrv_header_loc";
|
||||
@@ -46,7 +47,11 @@ run;
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=("&test2"="Content-type: application/text"),
|
||||
iftrue=("&test2"="Content-Type: application/text"),
|
||||
desc=Checking line was created,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
/* reset header so the test will pass */
|
||||
%let sasjs_stpsrv_header_loc=&orig_sasjs_stpsrv_header_loc;
|
||||
50
tests/serveronly/ms_createuser.test.sas
Normal file
50
tests/serveronly/ms_createuser.test.sas
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_createuser.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
@li ms_createuser.sas
|
||||
@li ms_getusers.sas
|
||||
|
||||
**/
|
||||
|
||||
%let user=%substr(%mf_getuniquename(),1,8);
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_createuser(&user,passwrd,outds=test1,mdebug=&sasjs_mdebug)
|
||||
%mp_assertscope(COMPARE
|
||||
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADPNUM MCLIB0_JADVLEN
|
||||
)
|
||||
|
||||
%let id=0;
|
||||
data _null_;
|
||||
set work.test1;
|
||||
call symputx('id',id);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&id>0),
|
||||
desc=Checking that user was created with an ID,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/* double check by querying the list of users */
|
||||
%ms_getusers(outds=work.test2)
|
||||
%let checkid=0;
|
||||
data _null_;
|
||||
set work.test2;
|
||||
where username="&user";
|
||||
call symputx('checkid',id);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&checkid=&id),
|
||||
desc=Checking that fetched user exists and has the same ID,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
28
tests/serveronly/ms_createwebservice.test.sas
Normal file
28
tests/serveronly/ms_createwebservice.test.sas
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_createwebservice.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mp_assertscope.sas
|
||||
@li ms_createwebservice.sas
|
||||
|
||||
**/
|
||||
|
||||
%let path=&mcTestAppLoc/ms_createwebservice;
|
||||
%let name=myservice;
|
||||
%let fref=%mf_getuniquefileref();
|
||||
|
||||
data _null_;
|
||||
file &fref lrecl=3000;
|
||||
put '%put hello world;';
|
||||
run;
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_createwebservice(path=&path,name=&name,code=&fref,mdebug=&sasjs_mdebug)
|
||||
%mp_assertscope(COMPARE)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
61
tests/serveronly/ms_deletefile.test.sas
Normal file
61
tests/serveronly/ms_deletefile.test.sas
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
@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 doesn't exist."),
|
||||
desc=Make sure the file was deleted,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
45
tests/serveronly/ms_getfile.test.sas
Normal file
45
tests/serveronly/ms_getfile.test.sas
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
23
tests/serveronly/ms_getusers.test.sas
Normal file
23
tests/serveronly/ms_getusers.test.sas
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_getusers.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li ms_getusers.sas
|
||||
@li mp_assertdsobs.sas
|
||||
@li mp_assertscope.sas
|
||||
|
||||
**/
|
||||
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_getusers(outds=work.test1,mdebug=&sasjs_mdebug)
|
||||
%mp_assertscope(COMPARE
|
||||
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADPNUM MCLIB0_JADVLEN
|
||||
)
|
||||
|
||||
%mp_assertdsobs(work.test1,test=ATLEAST 1)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,14 +3,32 @@
|
||||
@brief Testing ms_runstp.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li ms_runstp.sas
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
@li ms_createfile.sas
|
||||
@li ms_runstp.sas
|
||||
|
||||
**/
|
||||
|
||||
/* first, create an STP to run */
|
||||
filename stpcode temp;
|
||||
data _null_;
|
||||
file stpcode;
|
||||
put '%put hello world;';
|
||||
put '%put _all_;';
|
||||
run;
|
||||
|
||||
options mprint;
|
||||
%let fname=%mf_getuniquename();
|
||||
|
||||
%ms_createfile(/sasjs/tests/&fname..sas
|
||||
,inref=stpcode
|
||||
,mdebug=1
|
||||
)
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_runstp(/Public/app/frs/allan/services/common/appinit
|
||||
%ms_runstp(/sasjs/tests/&fname
|
||||
,debug=131
|
||||
,outref=weboot
|
||||
)
|
||||
@@ -24,20 +42,16 @@ data _null_;
|
||||
putlog _infile_;
|
||||
run;
|
||||
|
||||
data work.httpheaders;
|
||||
set webeen.httpheaders;
|
||||
call symputx('test1',content_type);
|
||||
run;
|
||||
|
||||
%let test1=0;
|
||||
data work.log;
|
||||
set webeen.log;
|
||||
put (_all_)(=);
|
||||
if _n_>10 then stop;
|
||||
if _n_>10 then call symputx('test1',1);
|
||||
run;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=("&test1"="application/json"),
|
||||
desc=Checking line was created,
|
||||
iftrue=("&test1"="1"),
|
||||
desc=Checking log was returned,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
87
tests/serveronly/ms_testservice.test.sas
Normal file
87
tests/serveronly/ms_testservice.test.sas
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_testservice.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li ms_createwebservice.sas
|
||||
@li ms_testservice.sas
|
||||
@li mp_assert.sas
|
||||
|
||||
**/
|
||||
|
||||
filename ft15f001 temp;
|
||||
parmcards4;
|
||||
%put Initialising sendObj: ;
|
||||
%put _all_;
|
||||
%webout(FETCH)
|
||||
%webout(OPEN)
|
||||
%macro x();
|
||||
%if (%symexist(sasjs_tables) and %length(&sasjs_tables)>0)
|
||||
%then %do i=1 %to %sysfunc(countw(&sasjs_tables));
|
||||
%let table=%scan(&sasjs_tables,&i);
|
||||
%webout(OBJ,&table,missing=STRING)
|
||||
%end;
|
||||
%else %do i=1 %to &_webin_file_count;
|
||||
%webout(OBJ,&&_webin_name&i,missing=STRING)
|
||||
%end;
|
||||
%mend x; %x()
|
||||
%webout(CLOSE)
|
||||
;;;;
|
||||
%put creating web service: &mcTestAppLoc/services;
|
||||
%ms_createwebservice(
|
||||
path=&mcTestAppLoc/services,
|
||||
name=sendObj,
|
||||
mdebug=&sasjs_mdebug
|
||||
)
|
||||
%put created web service: &mcTestAppLoc/services;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&syscc=0),
|
||||
desc=No errors after service creation,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/**
|
||||
* Test 1 - send a dataset
|
||||
*/
|
||||
data work.somedata1 work.somedata2;
|
||||
x=1;
|
||||
y=' t"w"o';
|
||||
z=.z;
|
||||
label x='x factor';
|
||||
output;
|
||||
run;
|
||||
|
||||
%ms_testservice(&mcTestAppLoc/services/sendObj,
|
||||
inputdatasets=work.somedata1 work.somedata2,
|
||||
debug=log,
|
||||
mdebug=1,
|
||||
outlib=testlib1,
|
||||
outref=test1
|
||||
)
|
||||
|
||||
%let test1=FAIL;
|
||||
data _null_;
|
||||
set testlib1.somedata1;
|
||||
if x=1 and y=' t"w"o' and z="Z" then call symputx('test1','PASS');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
|
||||
%let test2=FAIL;
|
||||
data _null_;
|
||||
set testlib1.somedata2;
|
||||
if x=1 and y=' t"w"o' and z="Z" then call symputx('test2','PASS');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&test1=PASS),
|
||||
desc=somedata1 created correctly,
|
||||
outds=work.test_results
|
||||
)
|
||||
%mp_assert(
|
||||
iftrue=(&test2=PASS),
|
||||
desc=somedata2 created correctly,
|
||||
outds=work.test_results
|
||||
)
|
||||
@@ -3,27 +3,34 @@
|
||||
@brief init file for tests
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_uid.sas
|
||||
@li mp_init.sas
|
||||
@li mv_webout.sas
|
||||
@li ms_webout.sas
|
||||
|
||||
**/
|
||||
|
||||
/* location in metadata or SAS Drive for temporary files */
|
||||
%let mcTestAppLoc=/Public/temp/macrocore;
|
||||
%let mcTestAppLoc=/tmp/tests/sasjs/core/%mf_uid();
|
||||
|
||||
/* set defaults */
|
||||
%mp_init()
|
||||
|
||||
%global _debug;
|
||||
options lrecl=80;
|
||||
|
||||
%global _debug sasjs_mdebug;
|
||||
|
||||
%let sasjs_mdebug=0;
|
||||
|
||||
%macro loglevel();
|
||||
%if "&_debug"="2477" or "&_debug"="fields,log,trace" %then %do;
|
||||
%if "&_debug"="2477" or "&_debug"="fields,log,trace" or "&_debug"="131"
|
||||
%then %do;
|
||||
%put debug mode activated;
|
||||
options mprint mprintnest;
|
||||
%let sasjs_mdebug=1;
|
||||
%end;
|
||||
%mend loglevel;
|
||||
|
||||
%loglevel()
|
||||
|
||||
%put Initialised &_program;
|
||||
%put _all_;
|
||||
%put _all_;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
%mp_assert(
|
||||
iftrue=(&syscc=0),
|
||||
desc=Checking final error condition,
|
||||
desc=Checking final err condition,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
52
tests/viyaonly/mv_deleteviyafolder.test.sas
Normal file
52
tests/viyaonly/mv_deleteviyafolder.test.sas
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
@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
|
||||
)
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
@li mv_createjob.sas
|
||||
@li mv_getjobcode.sas
|
||||
|
||||
@@ -27,11 +28,17 @@ 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;
|
||||
@@ -46,4 +53,4 @@ run;
|
||||
%mp_assert(
|
||||
iftrue=(&diditexist=NO),
|
||||
desc=Check if the code that was sent was successfully retrieved
|
||||
)
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
@li mv_createjob.sas
|
||||
@li mv_jobexecute.sas
|
||||
@li mv_jobwaitfor.sas
|
||||
@@ -49,8 +50,12 @@ data _null_;
|
||||
run;
|
||||
|
||||
%* Finally, fetch the log;
|
||||
%mv_getjoblog(uri=%str(&uri),outref=mylog)
|
||||
|
||||
%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
|
||||
)
|
||||
|
||||
data _null_;
|
||||
infile mylog end=eof;
|
||||
@@ -67,4 +72,4 @@ run;
|
||||
%mp_assert(
|
||||
iftrue=(%str(&found)=1),
|
||||
desc=Check if the log was still fetched even though endsas was submitted
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing mm_webout macro
|
||||
@brief Testing mv_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;
|
||||
@@ -38,4 +56,4 @@ run;
|
||||
%mp_assert(
|
||||
iftrue=(%str(&checkval)=%str(&sysvlong)),
|
||||
desc=Check if the sysvlong value was created
|
||||
)
|
||||
)
|
||||
|
||||
@@ -247,7 +247,7 @@ data _null_;
|
||||
put ' ';
|
||||
put '%if &action=OPEN %then %do; ';
|
||||
put ' options nobomfile; ';
|
||||
put ' data _null_;file &jref encoding=''utf-8'' ; ';
|
||||
put ' data _null_;file &jref encoding=''utf-8'' lrecl=200; ';
|
||||
put ' put ''{"PROCESSED_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''"''; ';
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
@@ -376,12 +376,23 @@ data _null_;
|
||||
put ' format _numeric_ bart.; ';
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &&typelong&i=char or &fmt=Y %then %do; ';
|
||||
put ' &&name&i=''"''!!trim(prxchange(''s/"/\"/'',-1, ';
|
||||
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
|
||||
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
|
||||
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
|
||||
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
|
||||
put ' )))))!!''"''; ';
|
||||
put ' if findc(&&name&i,''"\''!!''0A0D09000E0F01021011''x) then do; ';
|
||||
put ' &&name&i=''"''!!trim( ';
|
||||
put ' prxchange(''s/"/\\"/'',-1, /* double quote */ ';
|
||||
put ' prxchange(''s/\x0A/\n/'',-1, /* new line */ ';
|
||||
put ' prxchange(''s/\x0D/\r/'',-1, /* carriage return */ ';
|
||||
put ' prxchange(''s/\x09/\\t/'',-1, /* tab */ ';
|
||||
put ' prxchange(''s/\x00/\\u0000/'',-1, /* NUL */ ';
|
||||
put ' prxchange(''s/\x0E/\\u000E/'',-1, /* SS */ ';
|
||||
put ' prxchange(''s/\x0F/\\u000F/'',-1, /* SF */ ';
|
||||
put ' prxchange(''s/\x01/\\u0001/'',-1, /* SOH */ ';
|
||||
put ' prxchange(''s/\x02/\\u0002/'',-1, /* STX */ ';
|
||||
put ' prxchange(''s/\x10/\\u0010/'',-1, /* DLE */ ';
|
||||
put ' prxchange(''s/\x11/\\u0011/'',-1, /* DC1 */ ';
|
||||
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
|
||||
put ' ))))))))))))!!''"''; ';
|
||||
put ' end; ';
|
||||
put ' else &&name&i=quote(cats(&&name&i)); ';
|
||||
put ' %end; ';
|
||||
put ' %end; ';
|
||||
put ' run; ';
|
||||
@@ -447,6 +458,25 @@ data _null_;
|
||||
put ' run; ';
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
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 ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
put ' %quote(&user) ';
|
||||
put ' ';
|
||||
put '%mend mf_getuser; ';
|
||||
put '%macro mv_webout(action,ds,fref=_mvwtemp,dslabel=,fmt=Y,stream=Y,missing=NULL ';
|
||||
put ' ,showmeta=NO ';
|
||||
put '); ';
|
||||
@@ -454,7 +484,7 @@ data _null_;
|
||||
put ' sasjs_tables SYS_JES_JOB_URI; ';
|
||||
put '%if %index("&_debug",log) %then %let _debug=131; ';
|
||||
put ' ';
|
||||
put '%local i tempds; ';
|
||||
put '%local i tempds table; ';
|
||||
put '%let action=%upcase(&action); ';
|
||||
put ' ';
|
||||
put '%if &action=FETCH %then %do; ';
|
||||
@@ -469,60 +499,35 @@ data _null_;
|
||||
put ' %end; ';
|
||||
put ' ';
|
||||
put ' /* if the sasjs_tables param is passed, we expect param based upload */ ';
|
||||
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 ' %if %length(&sasjs_tables.X)>1 %then %do; ';
|
||||
put ' ';
|
||||
put ' /* now read in the data */ ';
|
||||
put ' /* convert data from macro variables to datasets */ ';
|
||||
put ' %do i=1 %to %sysfunc(countw(&sasjs_tables)); ';
|
||||
put ' %local table; %let table=%scan(&sasjs_tables,&i); ';
|
||||
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 ' 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 &table; ';
|
||||
put ' data work.&table; ';
|
||||
put ' infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd ';
|
||||
put ' termstr=crlf; ';
|
||||
put ' input &input_statement; ';
|
||||
@@ -623,13 +628,15 @@ data _null_;
|
||||
put ' put ",""_DEBUG"" : ""&_debug"" "; ';
|
||||
put ' put '',"_PROGRAM" : '' _PROGRAM ; ';
|
||||
put ' put ",""SYSCC"" : ""&syscc"" "; ';
|
||||
put ' put ",""SYSERRORTEXT"" : ""&syserrortext"" "; ';
|
||||
put ' syserrortext=quote(cats(symget(''SYSERRORTEXT''))); ';
|
||||
put ' put '',"SYSERRORTEXT" : '' syserrortext; ';
|
||||
put ' put ",""SYSHOSTNAME"" : ""&syshostname"" "; ';
|
||||
put ' put ",""SYSSCPL"" : ""&sysscpl"" "; ';
|
||||
put ' put ",""SYSSITE"" : ""&syssite"" "; ';
|
||||
put ' sysvlong=quote(trim(symget(''sysvlong''))); ';
|
||||
put ' put '',"SYSVLONG" : '' sysvlong; ';
|
||||
put ' put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" "; ';
|
||||
put ' syswarningtext=quote(cats(symget(''SYSWARNINGTEXT''))); ';
|
||||
put ' put '',"SYSWARNINGTEXT" : '' syswarningtext; ';
|
||||
put ' put '',"END_DTTM" : "'' "%sysfunc(datetime(),E8601DT26.6)" ''" ''; ';
|
||||
put ' length memsize $32; ';
|
||||
put ' memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)"; ';
|
||||
@@ -644,24 +651,6 @@ data _null_;
|
||||
put '%end; ';
|
||||
put ' ';
|
||||
put '%mend mv_webout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
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 ' %else %let user=%scan(&&&metavar,1,@); ';
|
||||
put ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
put ' %quote(&user) ';
|
||||
put ' ';
|
||||
put '%mend mf_getuser; ';
|
||||
/* WEBOUT END */
|
||||
put '/* if calling viya service with _job param, _program will conflict */';
|
||||
put '/* so it is provided by SASjs instead as __program */';
|
||||
|
||||
@@ -8,10 +8,16 @@
|
||||
%mv_deleteviyafolder(path=/Public/test)
|
||||
|
||||
|
||||
@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.
|
||||
@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
|
||||
|
||||
|
||||
@version VIYA V.03.04
|
||||
@@ -19,6 +25,7 @@
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mp_abort.sas
|
||||
@li mf_existds.sas
|
||||
@li mf_getplatform.sas
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@@ -29,6 +36,7 @@
|
||||
%macro mv_deleteviyafolder(path=
|
||||
,access_token_var=ACCESS_TOKEN
|
||||
,grant_type=sas_services
|
||||
,mdebug=0
|
||||
);
|
||||
%local oauth_bearer;
|
||||
%if &grant_type=detect %then %do;
|
||||
@@ -105,14 +113,17 @@ run;
|
||||
%let libref1a=%mf_getuniquelibref();
|
||||
libname &libref1a JSON fileref=&fname1a;
|
||||
|
||||
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;
|
||||
%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;
|
||||
|
||||
%put &sysmacroname: perform the delete operation ;
|
||||
%local fname2;
|
||||
@@ -133,9 +144,11 @@ run;
|
||||
%end;
|
||||
%else %put &sysmacroname: &path successfully deleted;
|
||||
|
||||
/* clear refs */
|
||||
filename &fname1 clear;
|
||||
filename &fname2 clear;
|
||||
libname &libref1 clear;
|
||||
%if &mdebug=0 %then %do;
|
||||
/* clear refs */
|
||||
filename &fname1 clear;
|
||||
filename &fname2 clear;
|
||||
libname &libref1 clear;
|
||||
%end;
|
||||
|
||||
%mend mv_deleteviyafolder;
|
||||
%mend mv_deleteviyafolder;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
,grant_type=sas_services
|
||||
,outds=work.viyagroups
|
||||
);
|
||||
%local oauth_bearer;
|
||||
%local oauth_bearer base_uri fname1 libref1;
|
||||
%if &grant_type=detect %then %do;
|
||||
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||
%else %let grant_type=sas_services;
|
||||
@@ -50,11 +50,10 @@
|
||||
)
|
||||
|
||||
options noquotelenmax;
|
||||
%local base_uri; /* location of rest apis */
|
||||
/* 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();
|
||||
|
||||
@@ -78,9 +77,8 @@ data &outds;
|
||||
run;
|
||||
|
||||
|
||||
|
||||
/* clear refs */
|
||||
filename &fname1 clear;
|
||||
libname &libref1 clear;
|
||||
|
||||
%mend mv_getgroups;
|
||||
%mend mv_getgroups;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
@li mf_getplatform.sas
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mv_getfoldermembers.sas
|
||||
@li ml_json.sas
|
||||
|
||||
**/
|
||||
|
||||
@@ -44,9 +43,9 @@
|
||||
,grant_type=sas_services
|
||||
,mdebug=0
|
||||
);
|
||||
%local dbg;
|
||||
%local dbg bufsize varcnt fname1 fname2 errmsg;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname entry vars:;
|
||||
%put &sysmacroname local entry vars:;
|
||||
%put _local_;
|
||||
%end;
|
||||
%else %let dbg=*;
|
||||
@@ -104,7 +103,6 @@ run;
|
||||
)
|
||||
|
||||
/* prepare request*/
|
||||
%local fname1;
|
||||
%let fname1=%mf_getuniquefileref();
|
||||
proc http method='GET' out=&fname1 &oauth_bearer
|
||||
url="&base_uri&joburi";
|
||||
@@ -114,37 +112,95 @@ proc http method='GET' out=&fname1 &oauth_bearer
|
||||
%end;
|
||||
;
|
||||
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;
|
||||
%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));
|
||||
|
||||
/* compile the lua JSON module */
|
||||
%ml_json()
|
||||
/* read using LUA - this allows the code to be of any length */
|
||||
%if &mdebug=1 %then %do;
|
||||
data _null_;
|
||||
infile &fname1;
|
||||
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)
|
||||
)
|
||||
|
||||
%let fname2=%mf_getuniquefileref();
|
||||
filename &fname2 temp ;
|
||||
|
||||
/* 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 */
|
||||
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())
|
||||
local job=resp["code"]
|
||||
outfile:write(job)
|
||||
io.close(infile)
|
||||
io.close(outfile)
|
||||
';
|
||||
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;
|
||||
run;
|
||||
%inc "&fpath3..lua";
|
||||
|
||||
%mp_abort(iftrue=("&syscc"="99")
|
||||
,mac=mv_getjobcode
|
||||
,msg=%str(&errmsg)
|
||||
)
|
||||
|
||||
/* export to desired destination */
|
||||
%if "&outref"="0" %then %do;
|
||||
data _null_;
|
||||
@@ -169,7 +225,6 @@ run;
|
||||
/* clear refs */
|
||||
filename &fname1 clear;
|
||||
filename &fname2 clear;
|
||||
filename &fname3 clear;
|
||||
%end;
|
||||
|
||||
%mend mv_getjobcode;
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
@li mp_abort.sas
|
||||
@li mf_getplatform.sas
|
||||
@li mf_existfileref.sas
|
||||
@li ml_json.sas
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
|
||||
**/
|
||||
|
||||
@@ -95,7 +96,7 @@
|
||||
,grant_type=sas_services
|
||||
,mdebug=0
|
||||
);
|
||||
%local dbg;
|
||||
%local dbg libref1 libref2 loglocation fname1 fname2;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname entry vars:;
|
||||
%put _local_;
|
||||
@@ -154,8 +155,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
|
||||
@@ -175,37 +176,19 @@ 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));
|
||||
|
||||
/* compile the lua JSON module */
|
||||
%ml_json()
|
||||
/* read using LUA - this allows the code to be of any length */
|
||||
%let libref1=%mf_getuniquelibref();
|
||||
libname &libref1 JSON fileref=&fname1;
|
||||
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())
|
||||
local logloc=resp["logLocation"]
|
||||
outfile:write(logloc)
|
||||
io.close(infile)
|
||||
io.close(outfile)
|
||||
';
|
||||
set &libref1..root;
|
||||
call symputx('loglocation',loglocation,'l');
|
||||
run;
|
||||
%inc "&fpath3..lua";
|
||||
/* get log path*/
|
||||
|
||||
/* validate log path*/
|
||||
%let errflg=1;
|
||||
%let errmsg=No entry in &fname2 fileref;
|
||||
%let errmsg=No loglocation entry in &fname1 fileref;
|
||||
data _null_;
|
||||
infile &fname2;
|
||||
input;
|
||||
uri=cats(_infile_);
|
||||
uri=symget('loglocation');
|
||||
if length(uri)<12 then do;
|
||||
call symputx('errflg',1);
|
||||
call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
|
||||
@@ -232,7 +215,7 @@ run;
|
||||
|
||||
/* we have a log uri - now fetch the log */
|
||||
%&dbg.put &sysmacroname: querying &base_uri&logloc/content;
|
||||
proc http method='GET' out=&fname1 &oauth_bearer
|
||||
proc http method='GET' out=&fname2 &oauth_bearer
|
||||
url="&base_uri&logloc/content?limit=10000";
|
||||
headers
|
||||
%if &grant_type=authorization_code %then %do;
|
||||
@@ -243,14 +226,14 @@ run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname: fetching log content from &base_uri&logloc/content;
|
||||
data _null_;infile &fname1;input;putlog _infile_;run;
|
||||
data _null_;infile &fname2;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=&fname1 &oauth_bearer
|
||||
proc http method='GET' out=&fname2 &oauth_bearer
|
||||
url="&base_uri&logloc/log/content?limit=10000";
|
||||
headers
|
||||
%if &grant_type=authorization_code %then %do;
|
||||
@@ -260,47 +243,32 @@ run;
|
||||
run;
|
||||
%if &mdebug=1 %then %do;
|
||||
%put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
|
||||
data _null_;infile &fname1;input;putlog _infile_;run;
|
||||
data _null_;infile &fname2;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 &fname1;input;putlog _infile_;run;
|
||||
data _null_;infile &fname2;input;putlog _infile_;run;
|
||||
%end;
|
||||
%mp_abort(mac=&sysmacroname
|
||||
,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||
)
|
||||
%end;
|
||||
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 */
|
||||
%let libref2=%mf_getuniquelibref();
|
||||
libname &libref2 JSON fileref=&fname2;
|
||||
data _null_;
|
||||
infile &fname2 end=last;
|
||||
file &outref mod;
|
||||
if _n_=1 then do;
|
||||
put "/** SASJS Viya Job Log Extract start: &uri **/";
|
||||
end;
|
||||
input;
|
||||
put _infile_;
|
||||
set &libref2..items end=last;
|
||||
%if &mdebug=1 %then %do;
|
||||
putlog _infile_;
|
||||
putlog line;
|
||||
%end;
|
||||
put line;
|
||||
if last then do;
|
||||
put "/** SASJS Viya Job Log Extract end: &uri **/";
|
||||
end;
|
||||
@@ -309,7 +277,8 @@ run;
|
||||
%if &mdebug=0 %then %do;
|
||||
filename &fname1 clear;
|
||||
filename &fname2 clear;
|
||||
filename &fname3 clear;
|
||||
libname &libref1 clear;
|
||||
libname &libref2 clear;
|
||||
%end;
|
||||
%else %do;
|
||||
%put &sysmacroname exit vars:;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
sasjs_tables SYS_JES_JOB_URI;
|
||||
%if %index("&_debug",log) %then %let _debug=131;
|
||||
|
||||
%local i tempds;
|
||||
%local i tempds table;
|
||||
%let action=%upcase(&action);
|
||||
|
||||
%if &action=FETCH %then %do;
|
||||
@@ -64,60 +64,35 @@
|
||||
%end;
|
||||
|
||||
/* if the sasjs_tables param is passed, we expect param based upload */
|
||||
%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;
|
||||
%if %length(&sasjs_tables.X)>1 %then %do;
|
||||
|
||||
/* now read in the data */
|
||||
/* convert data from macro variables to datasets */
|
||||
%do i=1 %to %sysfunc(countw(&sasjs_tables));
|
||||
%local table; %let table=%scan(&sasjs_tables,&i);
|
||||
%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;
|
||||
data _null_;
|
||||
infile "%sysfunc(pathname(work))/&table..csv" termstr=crlf ;
|
||||
input;
|
||||
if _n_=1 then call symputx('input_statement',_infile_);
|
||||
list;
|
||||
data &table;
|
||||
data work.&table;
|
||||
infile "%sysfunc(pathname(work))/&table..csv" firstobs=2 dsd
|
||||
termstr=crlf;
|
||||
input &input_statement;
|
||||
@@ -218,13 +193,15 @@
|
||||
put ",""_DEBUG"" : ""&_debug"" ";
|
||||
put ',"_PROGRAM" : ' _PROGRAM ;
|
||||
put ",""SYSCC"" : ""&syscc"" ";
|
||||
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
|
||||
syserrortext=quote(cats(symget('SYSERRORTEXT')));
|
||||
put ',"SYSERRORTEXT" : ' syserrortext;
|
||||
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
|
||||
put ",""SYSSCPL"" : ""&sysscpl"" ";
|
||||
put ",""SYSSITE"" : ""&syssite"" ";
|
||||
sysvlong=quote(trim(symget('sysvlong')));
|
||||
put ',"SYSVLONG" : ' sysvlong;
|
||||
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
|
||||
syswarningtext=quote(cats(symget('SYSWARNINGTEXT')));
|
||||
put ',"SYSWARNINGTEXT" : ' syswarningtext;
|
||||
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
|
||||
length memsize $32;
|
||||
memsize="%sysfunc(INPUTN(%sysfunc(getoption(memsize)), best.),sizekmg.)";
|
||||
|
||||
Reference in New Issue
Block a user