mirror of
https://github.com/sasjs/core.git
synced 2025-12-20 17:51:19 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3c333ea39 | |||
| ae72446f85 | |||
| 2b6bf4bd02 | |||
| 6dbb3760e0 | |||
| 200d9a5761 | |||
|
|
01a9a5b823 | ||
|
|
35eadd0e9d | ||
| 5cdca95216 | |||
|
|
81b75a32ed | ||
| b7f5a2ec00 | |||
| db859bbf1d | |||
| 27b56e8efd | |||
| 28ea218d02 | |||
| f356e1f351 | |||
| 4b375e0b8c | |||
| 7db207dd1c | |||
|
|
ffdfc57aa6 | ||
|
|
6fc8408988 | ||
|
|
eeb25fa5bc | ||
|
|
521d128afe | ||
|
|
0135dd6c8f | ||
|
|
1b66c59dc0 | ||
| 96be5c65dc | |||
| 8f6ef569e1 | |||
| ff45c5a8b8 | |||
| fb5f1c820a | |||
| c0e33175cf | |||
| 2bfa72f48f | |||
| fdc2e8ac8a |
44
.githooks/pre-commit
Executable file
44
.githooks/pre-commit
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# A hook script to verify that no filenames with capital letters are committed.
|
||||||
|
# Called by "git commit" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message if
|
||||||
|
# it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# Go through all the changed files (except for deleted and unmerged)
|
||||||
|
|
||||||
|
# Save exit code of last executed action
|
||||||
|
exit_code=0
|
||||||
|
|
||||||
|
# Check if file is one of SAS|DDL|CSV|SH and check for uppercase letters
|
||||||
|
mime_pattern="\.(sas|ddl|csv|sh)"
|
||||||
|
# Check for capital letters only in file names
|
||||||
|
extra_pattern="(^|/)[^/]*([A-Z]+)[^/]*\.[A-Za-z]{3}$"
|
||||||
|
# Grep git diff of files to commit
|
||||||
|
files=$( git diff --cached --find-copies --find-renames --name-only --diff-filter=ACMRTXBU |
|
||||||
|
grep -Ei "$mime_pattern" |
|
||||||
|
grep -E "$extra_pattern" )
|
||||||
|
echo "$files"
|
||||||
|
if [[ -n "$files" ]];
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
echo "Found files that contain capital letters."
|
||||||
|
echo "Please rename the following files in lowercase, and commit again:"
|
||||||
|
|
||||||
|
for file in $files; do
|
||||||
|
echo -e '- \E[0;32m'"$file"'\033[0m'
|
||||||
|
done
|
||||||
|
# Abort commit
|
||||||
|
exit_code=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$exit_code" == "0" ]; then
|
||||||
|
echo
|
||||||
|
echo -e '\033[1m'"Pre-commit validation Passed"'\033[0m'
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo -e '\033[1m'"Commit Aborted!"'\033[0m'
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
exit $exit_code
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,3 +1,9 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
sasjsbuild/
|
sasjsbuild/
|
||||||
|
|
||||||
|
# avoid filenames with spaces being committed to source control
|
||||||
|
**\ **
|
||||||
|
|
||||||
|
# ignore the mc_* files - containing macros for individual libraries
|
||||||
|
mc_*
|
||||||
10
.gitpod.dockerfile
Normal file
10
.gitpod.dockerfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
FROM gitpod/workspace-full
|
||||||
|
|
||||||
|
RUN sudo apt-get update \
|
||||||
|
&& sudo apt-get install -y \
|
||||||
|
doxygen \
|
||||||
|
&& npm i -g npm@latest \
|
||||||
|
&& npm i -g @sasjs/cli \
|
||||||
|
&& npm i \
|
||||||
|
&& sudo rm -rf /var/lib/apt/lists/*
|
||||||
8
.gitpod.yml
Normal file
8
.gitpod.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
tasks:
|
||||||
|
- init: npm i && clear
|
||||||
|
|
||||||
|
image:
|
||||||
|
file: .gitpod.dockerfile
|
||||||
|
vscode:
|
||||||
|
extensions:
|
||||||
|
- sasjs.sasjs-for-vscode@1.6.0:V4hJpMtbpekMcPRNhh4SXQ==
|
||||||
9
.vscode/.editorconfig
vendored
Normal file
9
.vscode/.editorconfig
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"search.exclude": {
|
||||||
|
"**/sasjsbuild/**": true,
|
||||||
|
"**/dist/**":true
|
||||||
|
},
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"trim_trailing_whitespace": true
|
||||||
|
}
|
||||||
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.detectIndentation": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.rulers": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"files.trimTrailingWhitespace": true
|
||||||
|
}
|
||||||
@@ -27,6 +27,5 @@ To contribute:
|
|||||||
1. Create your feature branch (`git checkout -b myfeature`)
|
1. Create your feature branch (`git checkout -b myfeature`)
|
||||||
2. Make your change
|
2. Make your change
|
||||||
3. Update the `all.sas` file (`python3 build.py`)
|
3. Update the `all.sas` file (`python3 build.py`)
|
||||||
4. Commit the change, using the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0) standard
|
4. Push and make a PR
|
||||||
5. Push and make a PR
|
|
||||||
|
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Macro Core
|
# Macro Core
|
||||||
|
|
||||||
Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of Application Development on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/CONTRIBUTING.md) are welcomed.
|
Much quality. Many standards. The **Macro Core** library exists to save time and development effort! Herein ye shall find a veritable host of MIT-licenced, production quality SAS macros. These are a mix of tools, utilities, functions and code generators that are useful in the context of [Application Development](https://sasapps.io) on the SAS platform (eg https://datacontroller.io). [Contributions](https://github.com/sasjs/core/blob/main/CONTRIBUTING.md) are welcomed.
|
||||||
|
|
||||||
You can download and compile them all in just two lines of SAS code:
|
You can download and compile them all in just two lines of SAS code:
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
|||||||
%inc mc;
|
%inc mc;
|
||||||
```
|
```
|
||||||
|
|
||||||
Documentation: https://sasjs.github.io/core.github.io/files.html
|
Documentation: https://core.sasjs.io
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
|||||||
## File Properties
|
## File Properties
|
||||||
|
|
||||||
- filenames much match macro names
|
- filenames much match macro names
|
||||||
- filenames must be lowercase
|
- filenames must be lowercase, without spaces
|
||||||
- macro names must be lowercase
|
- macro names must be lowercase
|
||||||
- one macro per file
|
- one macro per file
|
||||||
- prefixes:
|
- prefixes:
|
||||||
@@ -99,7 +99,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
|||||||
- unix style line endings (lf)
|
- unix style line endings (lf)
|
||||||
- individual lines should be no more than 80 characters long
|
- individual lines should be no more than 80 characters long
|
||||||
- UTF-8
|
- UTF-8
|
||||||
- no trailing white space
|
|
||||||
|
|
||||||
## Header Properties
|
## Header Properties
|
||||||
|
|
||||||
@@ -136,13 +136,15 @@ When contributing to this library, it is therefore important to ensure that all
|
|||||||
## Coding Standards
|
## Coding Standards
|
||||||
|
|
||||||
- Indentation = 2 spaces. No tabs!
|
- Indentation = 2 spaces. No tabs!
|
||||||
|
- no trailing white space
|
||||||
|
- no invisible characters, other than spaces. If invisibles are needed, use hex literals.
|
||||||
- Macro variables should not have the trailing dot (`&var` not `&var.`) unless necessary to prevent incorrect resolution
|
- Macro variables should not have the trailing dot (`&var` not `&var.`) unless necessary to prevent incorrect resolution
|
||||||
- The closing `%mend;` should not contain the macro name.
|
- The closing `%mend;` should **not** contain the macro name.
|
||||||
- All macros should be defined with brackets, even if no variables are needed - ie `%macro x();` not `%macro x;`
|
- All macros should be defined with brackets, even if no variables are needed - ie `%macro x();` not `%macro x;`
|
||||||
- Mandatory parameters should be positional, all optional parameters should be keyword (var=) style.
|
- Mandatory parameters should be positional, all optional parameters should be keyword (var=) style.
|
||||||
- All dataset references must be 2 level (eg `work.blah`, not `blah`). This is to avoid contention when options [DATASTMTCHK](https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000279064.htm)=ALLKEYWORDS is in effect.
|
- All dataset references must be 2 level (eg `work.blah`, not `blah`). This is to avoid contention when options [DATASTMTCHK](https://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000279064.htm)=ALLKEYWORDS is in effect.
|
||||||
- Avoid naming collisions! All macro variables should be local scope. Use system generated work tables where possible - eg `data ; set sashelp.class; run; data &output; set &syslast; run;`
|
- Avoid naming collisions! All macro variables should be local scope. Use system generated work tables where possible - eg `data ; set sashelp.class; run; data &output; set &syslast; run;`
|
||||||
- If you have a long-running SQL query, the use of a `quit;` statement is recommended in order to benefit from the timing statistics.
|
- The use of `quit;` for `proc sql` is optional unless you are looking to benefit from the timing statistics.
|
||||||
|
|
||||||
# General Notes
|
# General Notes
|
||||||
|
|
||||||
|
|||||||
664
all.sas
664
all.sas
@@ -1426,12 +1426,12 @@ Usage:
|
|||||||
|
|
||||||
%mend;/**
|
%mend;/**
|
||||||
@file
|
@file
|
||||||
@brief Creates a Unique ID based on system time in a friendly format
|
@brief Creates a unique ID based on system time in friendly format
|
||||||
@details format = YYYYMMDD_HHMMSSmmm_<sysjobid>_<3randomDigits>
|
@details format = YYYYMMDD_HHMMSSmmm_<sysjobid>_<3randomDigits>
|
||||||
|
|
||||||
%put %mf_uid();
|
%put %mf_uid();
|
||||||
|
|
||||||
@version 9.2
|
@version 9.3
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
**/
|
**/
|
||||||
@@ -1440,7 +1440,7 @@ Usage:
|
|||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%local today now;
|
%local today now;
|
||||||
%let today=%sysfunc(today(),yymmddn8.);
|
%let today=%sysfunc(today(),yymmddn8.);
|
||||||
%let now=%sysfunc(compress(%sysfunc(time(),time12.3),:.));
|
%let now=%sysfunc(compress(%sysfunc(time(),tod12.3),:.));
|
||||||
|
|
||||||
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
||||||
|
|
||||||
@@ -4027,6 +4027,15 @@ create table &outds (rename=(
|
|||||||
The output will be one cards file in the `outloc` directory per dataset in the
|
The output will be one cards file in the `outloc` directory per dataset in the
|
||||||
input `lib` library. If the `outloc` directory does not exist, it is created.
|
input `lib` library. If the `outloc` directory does not exist, it is created.
|
||||||
|
|
||||||
|
To create a single SAS file with the first 1000 records of each table in a
|
||||||
|
library you could use this syntax:
|
||||||
|
|
||||||
|
%mp_lib2cards(lib=sashelp
|
||||||
|
, outloc= /tmp
|
||||||
|
, outfile= myfile.sas
|
||||||
|
, maxobs= 1000
|
||||||
|
)
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_mkdir.sas
|
@li mf_mkdir.sas
|
||||||
@li mf_trimstr.sas
|
@li mf_trimstr.sas
|
||||||
@@ -7592,6 +7601,98 @@ run;
|
|||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
%mend;
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Deletes a library by Name
|
||||||
|
|
||||||
|
@details Used to delete a library.
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%* create a library in the home directory ;
|
||||||
|
%mm_createlibrary(
|
||||||
|
libname=My Temp Library,
|
||||||
|
libref=XXTEMPXX,
|
||||||
|
tree=/User Folders/&sysuserid,
|
||||||
|
directory=%sysfunc(pathname(work))
|
||||||
|
)
|
||||||
|
|
||||||
|
%* delete the library ;
|
||||||
|
%mm_deletelibrary(name=My Temp Library)
|
||||||
|
|
||||||
|
After running the above, the following will be shown in the log:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
@param [in] name= the name (not libref) of the library to be deleted
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mm_deletelibrary(
|
||||||
|
name=
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if library exists and get uri
|
||||||
|
*/
|
||||||
|
data _null_;
|
||||||
|
length type uri $256;
|
||||||
|
rc=metadata_resolve("omsobj:SASLibrary?@Name='&name'",type,uri);
|
||||||
|
call symputx('checktype',type,'l');
|
||||||
|
call symputx('liburi',uri,'l');
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
%if &checktype ne SASLibrary %then %do;
|
||||||
|
%put &sysmacroname: Library (&name) was not found, and so will not be deleted;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%local fname1 fname2;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
|
||||||
|
filename &fname1 temp lrecl=10000;
|
||||||
|
filename &fname2 temp lrecl=10000;
|
||||||
|
data _null_ ;
|
||||||
|
file &fname1 ;
|
||||||
|
put "<DeleteMetadata><Metadata><SASLibrary Id='&liburi'/>";
|
||||||
|
put "</Metadata><NS>SAS</NS><Flags>268436480</Flags><Options/>";
|
||||||
|
put "</DeleteMetadata>";
|
||||||
|
run ;
|
||||||
|
proc metadata in=&fname1 out=&fname2 verbose;run;
|
||||||
|
|
||||||
|
/* list the result */
|
||||||
|
data _null_;infile &fname2; input; list; run;
|
||||||
|
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check deletion
|
||||||
|
*/
|
||||||
|
%local isgone;
|
||||||
|
data _null_;
|
||||||
|
length type uri $256;
|
||||||
|
rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri);
|
||||||
|
call symputx('isgone',type,'l');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_abort(iftrue=(&isgone = SASLibrary)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Library (&name) NOT deleted)
|
||||||
|
)
|
||||||
|
|
||||||
|
%put &sysmacroname: Library &name (&liburi) was successfully deleted;
|
||||||
|
|
||||||
%mend;
|
%mend;
|
||||||
/**
|
/**
|
||||||
@file mm_deletestp.sas
|
@file mm_deletestp.sas
|
||||||
@@ -8096,20 +8197,117 @@ filename __outdoc clear;
|
|||||||
|
|
||||||
%mend;
|
%mend;
|
||||||
/**
|
/**
|
||||||
@file mm_getfoldertree.sas
|
@file
|
||||||
|
@brief Returns all direct child members of a particular folder
|
||||||
|
@details Displays the children for a particular folder, in a similar fashion
|
||||||
|
to the viya counterpart (mv_getfoldermembers.sas)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%mm_getfoldermembers(root=/, outds=rootfolders)
|
||||||
|
|
||||||
|
%mm_getfoldermembers(root=/User Folders/&sysuserid, outds=usercontent)
|
||||||
|
|
||||||
|
@param [in] root= the parent folder under which to return all contents
|
||||||
|
@param [out] outds= the dataset to create that contains the list of directories
|
||||||
|
@param [in] mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
|
<h4> Data Outputs </h4>
|
||||||
|
|
||||||
|
Example for `root=/`:
|
||||||
|
|
||||||
|
|metauri $17|metaname $256|metatype $32|
|
||||||
|
|---|---|---|
|
||||||
|
|A5XLSNXI.AA000001|Products |Folder|
|
||||||
|
|A5XLSNXI.AA000002|Shared Data |Folder|
|
||||||
|
|A5XLSNXI.AA000003|User Folders |Folder|
|
||||||
|
|A5XLSNXI.AA000004|System |Folder|
|
||||||
|
|A5XLSNXI.AA00003K|30.SASApps |Folder|
|
||||||
|
|A5XLSNXI.AA00006A|Public|Folder|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mm_getfoldertree.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
%macro mm_getfoldermembers(
|
||||||
|
root=
|
||||||
|
,outds=work.mm_getfoldertree
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%if "&root" = "/" %then %do;
|
||||||
|
%local fname1 fname2 fname3;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
%let fname3=%mf_getuniquefileref();
|
||||||
|
data _null_ ;
|
||||||
|
file &fname1 ;
|
||||||
|
put '<GetMetadataObjects>' ;
|
||||||
|
put '<Reposid>$METAREPOSITORY</Reposid>' ;
|
||||||
|
put '<Type>Tree</Type>' ;
|
||||||
|
put '<NS>SAS</NS>' ;
|
||||||
|
put '<Flags>388</Flags>' ;
|
||||||
|
put '<Options>' ;
|
||||||
|
put '<XMLSelect search="Tree[SoftwareComponents/SoftwareComponent'@;
|
||||||
|
put '[@Name=''BIP Service'']]"/>';
|
||||||
|
put '</Options>' ;
|
||||||
|
put '</GetMetadataObjects>' ;
|
||||||
|
run ;
|
||||||
|
proc metadata in=&fname1 out=&fname2 verbose;run;
|
||||||
|
|
||||||
|
/* create an XML map to read the response */
|
||||||
|
data _null_;
|
||||||
|
file &fname3;
|
||||||
|
put '<SXLEMAP version="1.2" name="SASFolders">';
|
||||||
|
put '<TABLE name="SASFolders">';
|
||||||
|
put '<TABLE-PATH syntax="XPath">//Objects/Tree</TABLE-PATH>';
|
||||||
|
put '<COLUMN name="metauri">><LENGTH>17</LENGTH>';
|
||||||
|
put '<PATH syntax="XPath">//Objects/Tree/@Id</PATH></COLUMN>';
|
||||||
|
put '<COLUMN name="metaname"><LENGTH>256</LENGTH>>';
|
||||||
|
put '<PATH syntax="XPath">//Objects/Tree/@Name</PATH></COLUMN>';
|
||||||
|
put '</TABLE></SXLEMAP>';
|
||||||
|
run;
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 xml xmlfileref=&fname2 xmlmap=&fname3;
|
||||||
|
|
||||||
|
data &outds;
|
||||||
|
length metatype $32;
|
||||||
|
retain metatype 'Folder';
|
||||||
|
set &libref1..sasfolders;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%mm_getfoldertree(root=&root, outds=&outds,depth=1)
|
||||||
|
data &outds;
|
||||||
|
set &outds(rename=(name=metaname publictype=metatype));
|
||||||
|
keep metaname metauri metatype;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend;
|
||||||
|
/**
|
||||||
|
@file
|
||||||
@brief Returns all folders / subfolder content for a particular root
|
@brief Returns all folders / subfolder content for a particular root
|
||||||
@details Shows all members and SubTrees recursively for a particular root.
|
@details Shows all members and SubTrees recursively for a particular root.
|
||||||
Note - for big sites, this returns a lot of data! So you may wish to reduce
|
Note - for big sites, this returns a lot of data! So you may wish to reduce
|
||||||
the logging to speed up the process (see example below)
|
the logging to speed up the process (see example below), OR - use mm_tree.sas
|
||||||
|
which uses proc metadata and is far more efficient.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
options ps=max nonotes nosource;
|
options ps=max nonotes nosource;
|
||||||
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
||||||
options notes source;
|
options notes source;
|
||||||
|
|
||||||
@param root= the parent folder under which to return all contents
|
@param [in] root= the parent folder under which to return all contents
|
||||||
@param outds= the dataset to create that contains the list of directories
|
@param [out] outds= the dataset to create that contains the list of directories
|
||||||
@param mDebug= set to 1 to show debug messages in the log
|
@param [in] mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
|
|
||||||
@@ -8157,7 +8355,7 @@ data &outds.TMP/view=&outds.TMP;
|
|||||||
__n1+1;
|
__n1+1;
|
||||||
/* Walk through all possible associations of this object. */
|
/* Walk through all possible associations of this object. */
|
||||||
__n2=1;
|
__n2=1;
|
||||||
if assoctype in ('Members','SubTrees') then
|
if assoctype in ('Members','SubTrees') then
|
||||||
do while(metadata_getnasn(pathuri,assoctype,__n2,metauri)>0);
|
do while(metadata_getnasn(pathuri,assoctype,__n2,metauri)>0);
|
||||||
__n2+1;
|
__n2+1;
|
||||||
call missing(name,publictype,MetadataUpdated,MetadataCreated);
|
call missing(name,publictype,MetadataUpdated,MetadataCreated);
|
||||||
@@ -8347,6 +8545,39 @@ run;
|
|||||||
options metarepository=&oldrepo;
|
options metarepository=&oldrepo;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
%mend;/**
|
||||||
|
@file
|
||||||
|
@brief Compares the metadata of a library with the physical tables
|
||||||
|
|
||||||
|
@param [out] prefix the dataset to create that contains the list of libraries
|
||||||
|
@param mDebug set to anything but 0 to show debug messages in the log
|
||||||
|
|
||||||
|
@test Create a temporary library as follows:
|
||||||
|
|
||||||
|
%
|
||||||
|
|
||||||
|
@details Creates a series of output tables that show the differences between
|
||||||
|
metadata and physical tables.
|
||||||
|
Each output can be created with an optional prefix.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@version 9.3
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mm_getlibmetadiffs
|
||||||
|
prefix=metadiff
|
||||||
|
,mdebug=0
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%if &mdebug = 0 %then %let mdebug=*;
|
||||||
|
|
||||||
|
&mdebug %put _local_;
|
||||||
|
|
||||||
|
|
||||||
%mend;/**
|
%mend;/**
|
||||||
@file
|
@file
|
||||||
@brief Creates a dataset with all metadata libraries
|
@brief Creates a dataset with all metadata libraries
|
||||||
@@ -10195,16 +10426,15 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%mend;/**
|
%mend;/**
|
||||||
@file mm_updatestpservertype.sas
|
@file
|
||||||
@brief Updates a type 2 stored process to run on STP or WKS context
|
@brief Updates a type 2 stored process to run on STP or WKS context
|
||||||
@details Only works on Type 2 (9.3 compatible) STPs
|
@details Only works on Type 2 (9.3 compatible) STPs
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%mm_updatestpservertype(target=/some/meta/path/myStoredProcess
|
%mm_updatestpservertype(target=/some/meta/path/myStoredProcess
|
||||||
,type=WKS)
|
,type=WKS)
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
|
||||||
|
|
||||||
@param target= full path to the STP being deleted
|
@param target= full path to the STP being deleted
|
||||||
@param type= Either WKS or STP depending on whether Workspace or Stored Process
|
@param type= Either WKS or STP depending on whether Workspace or Stored Process
|
||||||
@@ -10269,31 +10499,40 @@ run;
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%mm_updatestpsourcecode(stp=/my/metadata/path/mystpname
|
%mm_updatestpsourcecode(stp=/my/metadata/path/mystpname
|
||||||
,stpcode="/file/system/source.sas")
|
,stpcode="/file/system/source.sas")
|
||||||
|
|
||||||
|
@param [in] stp= the BIP Tree folder path plus Stored Process Name
|
||||||
@param stp= the BIP Tree folder path plus Stored Process Name
|
@param [in] stpcode= the source file (or fileref) containing the SAS code to load
|
||||||
@param stpcode= the source file (or fileref) containing the SAS code to load
|
|
||||||
into the stp. For multiple files, they should simply be concatenated first.
|
into the stp. For multiple files, they should simply be concatenated first.
|
||||||
@param minify= set to YES in order to strip comments, blank lines, and CRLFs.
|
@param [in] minify= set to YES in order to strip comments, blank lines, and CRLFs.
|
||||||
|
|
||||||
@param frefin= change default inref if it clashes with an existing one
|
@param frefin= deprecated - a unique fileref is now always used
|
||||||
@param frefout= change default outref if it clashes with an existing one
|
@param frefout= deprecated - a unique fileref is now always used
|
||||||
@param mDebug= set to 1 to show debug messages in the log
|
@param mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
@version 9.3
|
@version 9.3
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mm_updatestpsourcecode(stp=
|
%macro mm_updatestpsourcecode(stp=
|
||||||
,stpcode=
|
,stpcode=
|
||||||
,minify=NO
|
,minify=NO
|
||||||
|
,mdebug=0
|
||||||
|
/* deprecated */
|
||||||
,frefin=inmeta
|
,frefin=inmeta
|
||||||
,frefout=outmeta
|
,frefout=outmeta
|
||||||
,mdebug=0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
%if &frefin ne inmeta or &frefout ne outmeta %then %do;
|
||||||
|
%put %str(WARN)ING: the frefin and frefout parameters will be deprecated in
|
||||||
|
an upcoming release.;
|
||||||
|
%end;
|
||||||
|
|
||||||
/* first, check if STP exists */
|
/* first, check if STP exists */
|
||||||
%local tsuri;
|
%local tsuri;
|
||||||
%let tsuri=stopifempty ;
|
%let tsuri=stopifempty ;
|
||||||
@@ -10331,7 +10570,9 @@ run;
|
|||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
filename &frefin temp lrecl=32767;
|
%local frefin frefout;
|
||||||
|
%let frefin=%mf_getuniquefileref();
|
||||||
|
%let frefout=%mf_getuniquefileref();
|
||||||
|
|
||||||
/* write header XML */
|
/* write header XML */
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -10344,7 +10585,7 @@ run;
|
|||||||
/* write contents */
|
/* write contents */
|
||||||
%if %length(&stpcode)>2 %then %do;
|
%if %length(&stpcode)>2 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
file &frefin mod;
|
file &frefin lrecl=32767 mod;
|
||||||
infile &stpcode lrecl=32767;
|
infile &stpcode lrecl=32767;
|
||||||
length outstr $32767;
|
length outstr $32767;
|
||||||
input outstr ;
|
input outstr ;
|
||||||
@@ -10373,9 +10614,6 @@ data _null_;
|
|||||||
</UpdateMetadata>";
|
</UpdateMetadata>";
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
filename &frefout temp;
|
|
||||||
|
|
||||||
proc metadata in= &frefin out=&frefout;
|
proc metadata in= &frefin out=&frefout;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -10387,6 +10625,10 @@ run;
|
|||||||
put _infile_;
|
put _infile_;
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
%else %do;
|
||||||
|
filename &frefin clear;
|
||||||
|
filename &frefout clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
%mend;/**
|
%mend;/**
|
||||||
@file mm_webout.sas
|
@file mm_webout.sas
|
||||||
@@ -10829,7 +11071,314 @@ options noquotelenmax;
|
|||||||
libname &libref1 clear;
|
libname &libref1 clear;
|
||||||
%end;
|
%end;
|
||||||
%mend;/**
|
%mend;/**
|
||||||
@file mv_createwebservice.sas
|
@file
|
||||||
|
@brief Creates a Viya Job
|
||||||
|
@details
|
||||||
|
Code is passed in as one or more filerefs.
|
||||||
|
|
||||||
|
%* Step 1 - compile macros ;
|
||||||
|
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
||||||
|
%inc mc;
|
||||||
|
|
||||||
|
%* Step 2 - Create some SAS code and add it to a job;
|
||||||
|
filename ft15f001 temp;
|
||||||
|
parmcards4;
|
||||||
|
data some_code;
|
||||||
|
set sashelp.class;
|
||||||
|
run;
|
||||||
|
;;;;
|
||||||
|
%mv_createjob(path=/Public/app/sasjstemp/jobs/myjobs,name=myjob)
|
||||||
|
|
||||||
|
The path to the job will then be shown in the log, eg as follows:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mv_createfolder.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getplatform.sas
|
||||||
|
@li mf_isblank.sas
|
||||||
|
@li mv_deletejes.sas
|
||||||
|
|
||||||
|
@param path= The full path (on SAS Drive) where the job will be created
|
||||||
|
@param name= The name of the job
|
||||||
|
@param desc= The description of the job
|
||||||
|
@param precode= Space separated list of filerefs, pointing to the code that
|
||||||
|
needs to be attached to the beginning of the job
|
||||||
|
@param code= Fileref(s) of the actual code to be added
|
||||||
|
@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 replace= select NO to avoid replacing any existing job in that location
|
||||||
|
@param contextname= Choose a specific context on which to run the Job. Leave
|
||||||
|
blank to use the default context. From Viya 3.5 it is possible to configure
|
||||||
|
a shared context - see
|
||||||
|
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
|
||||||
|
|
||||||
|
@version VIYA V.03.04
|
||||||
|
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mv_createjob(path=
|
||||||
|
,name=
|
||||||
|
,desc=Created by the mv_createjob.sas macro
|
||||||
|
,precode=
|
||||||
|
,code=ft15f001
|
||||||
|
,access_token_var=ACCESS_TOKEN
|
||||||
|
,grant_type=sas_services
|
||||||
|
,replace=YES
|
||||||
|
,debug=0
|
||||||
|
,contextname=
|
||||||
|
);
|
||||||
|
%local oauth_bearer;
|
||||||
|
%if &grant_type=detect %then %do;
|
||||||
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
|
%else %let grant_type=sas_services;
|
||||||
|
%end;
|
||||||
|
%if &grant_type=sas_services %then %do;
|
||||||
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
|
%let &access_token_var=;
|
||||||
|
%end;
|
||||||
|
%put &sysmacroname: grant_type=&grant_type;
|
||||||
|
|
||||||
|
/* initial validation checking */
|
||||||
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
|
and &grant_type ne sas_services
|
||||||
|
)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Invalid value for grant_type: &grant_type)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%mf_isblank(&path)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(path value must be provided)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%length(&path)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(path value must be provided)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%mf_isblank(&name)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(name value must be provided)
|
||||||
|
)
|
||||||
|
|
||||||
|
options noquotelenmax;
|
||||||
|
|
||||||
|
* remove any trailing slash ;
|
||||||
|
%if "%substr(&path,%length(&path),1)" = "/" %then
|
||||||
|
%let path=%substr(&path,1,%length(&path)-1);
|
||||||
|
|
||||||
|
/* ensure folder exists */
|
||||||
|
%put &sysmacroname: Path &path being checked / created;
|
||||||
|
%mv_createfolder(path=&path)
|
||||||
|
|
||||||
|
%local base_uri; /* location of rest apis */
|
||||||
|
%let base_uri=%mf_getplatform(VIYARESTAPI);
|
||||||
|
|
||||||
|
/* fetching folder details for provided path */
|
||||||
|
%local fname1;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
proc http method='GET' out=&fname1 &oauth_bearer
|
||||||
|
url="&base_uri/folders/folders/@item?path=&path";
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
headers "Authorization"="Bearer &&&access_token_var";
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
%if &debug %then %do;
|
||||||
|
data _null_;
|
||||||
|
infile &fname1;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* path exists. Grab follow on link to check members */
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 JSON fileref=&fname1;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
set &libref1..links;
|
||||||
|
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
|
||||||
|
else if rel='self' then call symputx('parentFolderUri',href,'l');
|
||||||
|
run;
|
||||||
|
data _null_;
|
||||||
|
set &libref1..root;
|
||||||
|
call symputx('folderid',id,'l');
|
||||||
|
run;
|
||||||
|
%local fname2;
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
proc http method='GET'
|
||||||
|
out=&fname2
|
||||||
|
&oauth_bearer
|
||||||
|
url=%unquote(%superq(membercheck));
|
||||||
|
headers
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
'Accept'='application/vnd.sas.collection+json'
|
||||||
|
'Accept-Language'='string';
|
||||||
|
%if &debug=1 %then %do;
|
||||||
|
debug level = 3;
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
/*data _null_;infile &fname2;input;putlog _infile_;run;*/
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
|
||||||
|
%if %upcase(&replace)=YES %then %do;
|
||||||
|
%mv_deletejes(path=&path, name=&name)
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
/* check that job does not already exist in that folder */
|
||||||
|
%local libref2;
|
||||||
|
%let libref2=%mf_getuniquelibref();
|
||||||
|
libname &libref2 JSON fileref=&fname2;
|
||||||
|
%local exists; %let exists=0;
|
||||||
|
data _null_;
|
||||||
|
set &libref2..items;
|
||||||
|
if contenttype='jobDefinition' and upcase(name)="%upcase(&name)" then
|
||||||
|
call symputx('exists',1,'l');
|
||||||
|
run;
|
||||||
|
%mp_abort(iftrue=(&exists=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Job &name already exists in &path)
|
||||||
|
)
|
||||||
|
libname &libref2 clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* set up the body of the request to create the service */
|
||||||
|
%local fname3;
|
||||||
|
%let fname3=%mf_getuniquefileref();
|
||||||
|
data _null_;
|
||||||
|
file &fname3 TERMSTR=' ';
|
||||||
|
length string $32767;
|
||||||
|
string=cats('{"version": 0,"name":"'
|
||||||
|
,"&name"
|
||||||
|
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
|
||||||
|
,',"type":"CHARACTER","defaultValue":"false"}');
|
||||||
|
context=quote(cats(symget('contextname')));
|
||||||
|
if context ne '""' then do;
|
||||||
|
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":'
|
||||||
|
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
|
||||||
|
end;
|
||||||
|
string=cats(string,'],"code":"');
|
||||||
|
put string;
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
/* insert the code, escaping double quotes and carriage returns */
|
||||||
|
%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_;
|
||||||
|
length filein 8 fileid 8;
|
||||||
|
filein = fopen("&fref","I",1,"B");
|
||||||
|
fileid = fopen("&fname3","A",1,"B");
|
||||||
|
rec = "20"x;
|
||||||
|
do while(fread(filein)=0);
|
||||||
|
rc = fget(filein,rec,1);
|
||||||
|
if rec='"' then do; /* DOUBLE QUOTE */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'"');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='0A'x then do; /* LF */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'n');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='0D'x then do; /* CR */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'r');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='09'x then do; /* TAB */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'t');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='5C'x then do; /* BACKSLASH */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
rc =fput(fileid,rec);
|
||||||
|
rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
rc=fclose(filein);
|
||||||
|
rc=fclose(fileid);
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* finish off the body of the code file loaded to JES */
|
||||||
|
data _null_;
|
||||||
|
file &fname3 mod TERMSTR=' ';
|
||||||
|
put '"}';
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* now we can create the job!! */
|
||||||
|
%local fname4;
|
||||||
|
%let fname4=%mf_getuniquefileref();
|
||||||
|
proc http method='POST'
|
||||||
|
in=&fname3
|
||||||
|
out=&fname4
|
||||||
|
&oauth_bearer
|
||||||
|
url="&base_uri/jobDefinitions/definitions?parentFolderUri=&parentFolderUri";
|
||||||
|
headers 'Content-Type'='application/vnd.sas.job.definition+json'
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
"Accept"="application/vnd.sas.job.definition+json";
|
||||||
|
%if &debug=1 %then %do;
|
||||||
|
debug level = 3;
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
/*data _null_;infile &fname4;input;putlog _infile_;run;*/
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
/* clear refs */
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
filename &fname3 clear;
|
||||||
|
filename &fname4 clear;
|
||||||
|
libname &libref1 clear;
|
||||||
|
|
||||||
|
/* get the url so we can give a helpful log message */
|
||||||
|
%local url;
|
||||||
|
data _null_;
|
||||||
|
if symexist('_baseurl') then do;
|
||||||
|
url=symget('_baseurl');
|
||||||
|
if subpad(url,length(url)-9,9)='SASStudio'
|
||||||
|
then url=substr(url,1,length(url)-11);
|
||||||
|
else url="&systcpiphostname";
|
||||||
|
end;
|
||||||
|
else url="&systcpiphostname";
|
||||||
|
call symputx('url',url);
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
%put &sysmacroname: Job &name successfully created in &path;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
%put &sysmacroname: Check it out here:;
|
||||||
|
%put &sysmacroname:;%put;
|
||||||
|
%put &url/SASJobExecution?_PROGRAM=&path/&name;%put;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
|
||||||
|
%mend;
|
||||||
|
/**
|
||||||
|
@file
|
||||||
@brief Creates a JobExecution web service if it doesn't already exist
|
@brief Creates a JobExecution web service if it doesn't already exist
|
||||||
@details
|
@details
|
||||||
Code is passed in as one or more filerefs.
|
Code is passed in as one or more filerefs.
|
||||||
@@ -11396,23 +11945,23 @@ run;
|
|||||||
rec = "20"x;
|
rec = "20"x;
|
||||||
do while(fread(filein)=0);
|
do while(fread(filein)=0);
|
||||||
rc = fget(filein,rec,1);
|
rc = fget(filein,rec,1);
|
||||||
if rec='"' then do;
|
if rec='"' then do; /* DOUBLE QUOTE */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'"');rc =fwrite(fileid);
|
rc =fput(fileid,'"');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='0A'x then do;
|
else if rec='0A'x then do; /* LF */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
|
||||||
rc =fput(fileid,'r');rc =fwrite(fileid);
|
|
||||||
end;
|
|
||||||
else if rec='0D'x then do;
|
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'n');rc =fwrite(fileid);
|
rc =fput(fileid,'n');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='09'x then do;
|
else if rec='0D'x then do; /* CR */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'r');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='09'x then do; /* TAB */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'t');rc =fwrite(fileid);
|
rc =fput(fileid,'t');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='5C'x then do;
|
else if rec='5C'x then do; /* BACKSLASH */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
@@ -13486,6 +14035,8 @@ libname &libref;
|
|||||||
@li sas_services - will use oauth_bearer=sas_services
|
@li sas_services - will use oauth_bearer=sas_services
|
||||||
@param [in] inds= The input dataset containing a list of jobs and parameters
|
@param [in] inds= The input dataset containing a list of jobs and parameters
|
||||||
@param [in] maxconcurrency= The max number of parallel jobs to run. Default=8.
|
@param [in] maxconcurrency= The max number of parallel jobs to run. Default=8.
|
||||||
|
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
||||||
|
succcessfully
|
||||||
@param [in] mdebug= set to 1 to enable DEBUG messages
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
@param [out] outds= The output dataset containing the results
|
@param [out] outds= The output dataset containing the results
|
||||||
@param [out] outref= The output fileref to which to append the log file(s).
|
@param [out] outref= The output fileref to which to append the log file(s).
|
||||||
@@ -13509,6 +14060,7 @@ libname &libref;
|
|||||||
,access_token_var=ACCESS_TOKEN
|
,access_token_var=ACCESS_TOKEN
|
||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
,outref=0
|
,outref=0
|
||||||
|
,raise_err=0
|
||||||
,mdebug=0
|
,mdebug=0
|
||||||
);
|
);
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
@@ -13687,7 +14239,8 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
%end;
|
%end;
|
||||||
%if &jid=&jcnt %then %do;
|
%if &jid=&jcnt %then %do;
|
||||||
/* we are at the end of the loop - time to see which jobs have finished */
|
/* we are at the end of the loop - time to see which jobs have finished */
|
||||||
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref)
|
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref
|
||||||
|
,raise_err=&raise_err)
|
||||||
%local done;
|
%local done;
|
||||||
%let done=%mf_nobs(&jdswaitfor);
|
%let done=%mf_nobs(&jdswaitfor);
|
||||||
%if &done>0 %then %do;
|
%if &done>0 %then %do;
|
||||||
@@ -13794,6 +14347,8 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
following format: `/jobExecution/jobs/&JOBID./state` and the corresponding
|
following format: `/jobExecution/jobs/&JOBID./state` and the corresponding
|
||||||
job name. The uri should be in a `uri` variable, and the job path/name
|
job name. The uri should be in a `uri` variable, and the job path/name
|
||||||
should be in a `_program` variable.
|
should be in a `_program` variable.
|
||||||
|
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
||||||
|
succcessfully
|
||||||
@param [out] outds= The output dataset containing the list of states by job
|
@param [out] outds= The output dataset containing the list of states by job
|
||||||
(default=work.mv_jobexecute)
|
(default=work.mv_jobexecute)
|
||||||
@param [out] outref= A fileref to which the spawned job logs should be appended.
|
@param [out] outref= A fileref to which the spawned job logs should be appended.
|
||||||
@@ -13805,6 +14360,7 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@li mf_getplatform.sas
|
@li mf_getplatform.sas
|
||||||
@li mf_getuniquefileref.sas
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
@li mf_existvar.sas
|
@li mf_existvar.sas
|
||||||
@li mf_nobs.sas
|
@li mf_nobs.sas
|
||||||
@li mv_getjoblog.sas
|
@li mv_getjoblog.sas
|
||||||
@@ -13817,6 +14373,7 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
,inds=0
|
,inds=0
|
||||||
,outds=work.mv_jobwaitfor
|
,outds=work.mv_jobwaitfor
|
||||||
,outref=0
|
,outref=0
|
||||||
|
,raise_err=0
|
||||||
);
|
);
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
@@ -13860,7 +14417,7 @@ options noquotelenmax;
|
|||||||
data _null_;
|
data _null_;
|
||||||
length jobparams $32767;
|
length jobparams $32767;
|
||||||
set &inds end=last;
|
set &inds end=last;
|
||||||
call symputx(cats('joburi',_n_),substr(uri,1,55)!!'/state','l');
|
call symputx(cats('joburi',_n_),substr(uri,1,55),'l');
|
||||||
call symputx(cats('jobname',_n_),_program,'l');
|
call symputx(cats('jobname',_n_),_program,'l');
|
||||||
call symputx(cats('jobparams',_n_),jobparams,'l');
|
call symputx(cats('jobparams',_n_),jobparams,'l');
|
||||||
if last then call symputx('uricnt',_n_,'l');
|
if last then call symputx('uricnt',_n_,'l');
|
||||||
@@ -13875,7 +14432,7 @@ run;
|
|||||||
%let fname0=%mf_getuniquefileref();
|
%let fname0=%mf_getuniquefileref();
|
||||||
|
|
||||||
data &outds;
|
data &outds;
|
||||||
format _program uri $128. state $32. timestamp datetime19. jobparams $32767.;
|
format _program uri $128. state $32. stateDetails $32. timestamp datetime19. jobparams $32767.;
|
||||||
stop;
|
stop;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -13883,7 +14440,7 @@ run;
|
|||||||
%do i=1 %to &uricnt;
|
%do i=1 %to &uricnt;
|
||||||
%if "&&joburi&i" ne "0" %then %do;
|
%if "&&joburi&i" ne "0" %then %do;
|
||||||
proc http method='GET' out=&fname0 &oauth_bearer url="&base_uri/&&joburi&i";
|
proc http method='GET' out=&fname0 &oauth_bearer url="&base_uri/&&joburi&i";
|
||||||
headers "Accept"="text/plain"
|
headers "Accept"="application/json"
|
||||||
%if &grant_type=authorization_code %then %do;
|
%if &grant_type=authorization_code %then %do;
|
||||||
"Authorization"="Bearer &&&access_token_var"
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
%end; ;
|
%end; ;
|
||||||
@@ -13897,12 +14454,20 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%let status=notset;
|
%let status=notset;
|
||||||
|
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 json fileref=&fname0;
|
||||||
|
|
||||||
data _null_;
|
data _null_;
|
||||||
infile &fname0;
|
length state stateDetails $32;
|
||||||
input;
|
set &libref1..root;
|
||||||
call symputx('status',_infile_,'l');
|
call symputx('status',state,'l');
|
||||||
|
call symputx('stateDetails',stateDetails,'l');
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
libname &libref1 clear;
|
||||||
|
|
||||||
%if &status=completed or &status=failed or &status=canceled %then %do;
|
%if &status=completed or &status=failed or &status=canceled %then %do;
|
||||||
%local plainuri;
|
%local plainuri;
|
||||||
%let plainuri=%substr(&&joburi&i,1,55);
|
%let plainuri=%substr(&&joburi&i,1,55);
|
||||||
@@ -13911,6 +14476,7 @@ run;
|
|||||||
_program="&&jobname&i",
|
_program="&&jobname&i",
|
||||||
uri="&plainuri",
|
uri="&plainuri",
|
||||||
state="&status",
|
state="&status",
|
||||||
|
stateDetails=symget("stateDetails"),
|
||||||
timestamp=datetime(),
|
timestamp=datetime(),
|
||||||
jobparams=symget("jobparams&i");
|
jobparams=symget("jobparams&i");
|
||||||
%let joburi&i=0; /* do not re-check */
|
%let joburi&i=0; /* do not re-check */
|
||||||
@@ -13929,6 +14495,16 @@ run;
|
|||||||
,msg=%str(status &status not expected!!)
|
,msg=%str(status &status not expected!!)
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
%if (&raise_err) %then %do;
|
||||||
|
%if (&status = canceled or &status = failed or %length(&stateDetails)>0) %then %do;
|
||||||
|
%if ("&stateDetails" = "%str(war)ning") %then %let SYSCC=4;
|
||||||
|
%else %let SYSCC=5;
|
||||||
|
%put %str(ERR)OR: Job &&jobname&i. did not complete successfully. &stateDetails;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
%end;
|
%end;
|
||||||
%if &i=&uricnt %then %do;
|
%if &i=&uricnt %then %do;
|
||||||
%local goback;
|
%local goback;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
@brief Creates a Unique ID based on system time in a friendly format
|
@brief Creates a unique ID based on system time in friendly format
|
||||||
@details format = YYYYMMDD_HHMMSSmmm_<sysjobid>_<3randomDigits>
|
@details format = YYYYMMDD_HHMMSSmmm_<sysjobid>_<3randomDigits>
|
||||||
|
|
||||||
%put %mf_uid();
|
%put %mf_uid();
|
||||||
|
|
||||||
@version 9.2
|
@version 9.3
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
**/
|
**/
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
)/*/STORE SOURCE*/;
|
)/*/STORE SOURCE*/;
|
||||||
%local today now;
|
%local today now;
|
||||||
%let today=%sysfunc(today(),yymmddn8.);
|
%let today=%sysfunc(today(),yymmddn8.);
|
||||||
%let now=%sysfunc(compress(%sysfunc(time(),time12.3),:.));
|
%let now=%sysfunc(compress(%sysfunc(time(),tod12.3),:.));
|
||||||
|
|
||||||
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
&today._&now._&sysjobid._%sysevalf(%sysfunc(ranuni(0))*999,CEIL)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
The output will be one cards file in the `outloc` directory per dataset in the
|
The output will be one cards file in the `outloc` directory per dataset in the
|
||||||
input `lib` library. If the `outloc` directory does not exist, it is created.
|
input `lib` library. If the `outloc` directory does not exist, it is created.
|
||||||
|
|
||||||
|
To create a single SAS file with the first 1000 records of each table in a
|
||||||
|
library you could use this syntax:
|
||||||
|
|
||||||
|
%mp_lib2cards(lib=sashelp
|
||||||
|
, outloc= /tmp
|
||||||
|
, outfile= myfile.sas
|
||||||
|
, maxobs= 1000
|
||||||
|
)
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
@li mf_mkdir.sas
|
@li mf_mkdir.sas
|
||||||
@li mf_trimstr.sas
|
@li mf_trimstr.sas
|
||||||
|
|||||||
92
meta/mm_deletelibrary.sas
Normal file
92
meta/mm_deletelibrary.sas
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Deletes a library by Name
|
||||||
|
|
||||||
|
@details Used to delete a library.
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%* create a library in the home directory ;
|
||||||
|
%mm_createlibrary(
|
||||||
|
libname=My Temp Library,
|
||||||
|
libref=XXTEMPXX,
|
||||||
|
tree=/User Folders/&sysuserid,
|
||||||
|
directory=%sysfunc(pathname(work))
|
||||||
|
)
|
||||||
|
|
||||||
|
%* delete the library ;
|
||||||
|
%mm_deletelibrary(name=My Temp Library)
|
||||||
|
|
||||||
|
After running the above, the following will be shown in the log:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
@param [in] name= the name (not libref) of the library to be deleted
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mp_abort.sas
|
||||||
|
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mm_deletelibrary(
|
||||||
|
name=
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if library exists and get uri
|
||||||
|
*/
|
||||||
|
data _null_;
|
||||||
|
length type uri $256;
|
||||||
|
rc=metadata_resolve("omsobj:SASLibrary?@Name='&name'",type,uri);
|
||||||
|
call symputx('checktype',type,'l');
|
||||||
|
call symputx('liburi',uri,'l');
|
||||||
|
putlog (_all_)(=);
|
||||||
|
run;
|
||||||
|
%if &checktype ne SASLibrary %then %do;
|
||||||
|
%put &sysmacroname: Library (&name) was not found, and so will not be deleted;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%local fname1 fname2;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
|
||||||
|
filename &fname1 temp lrecl=10000;
|
||||||
|
filename &fname2 temp lrecl=10000;
|
||||||
|
data _null_ ;
|
||||||
|
file &fname1 ;
|
||||||
|
put "<DeleteMetadata><Metadata><SASLibrary Id='&liburi'/>";
|
||||||
|
put "</Metadata><NS>SAS</NS><Flags>268436480</Flags><Options/>";
|
||||||
|
put "</DeleteMetadata>";
|
||||||
|
run ;
|
||||||
|
proc metadata in=&fname1 out=&fname2 verbose;run;
|
||||||
|
|
||||||
|
/* list the result */
|
||||||
|
data _null_;infile &fname2; input; list; run;
|
||||||
|
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check deletion
|
||||||
|
*/
|
||||||
|
%local isgone;
|
||||||
|
data _null_;
|
||||||
|
length type uri $256;
|
||||||
|
rc=metadata_resolve("omsobj:SASLibrary?@Id='&liburi'",type,uri);
|
||||||
|
call symputx('isgone',type,'l');
|
||||||
|
run;
|
||||||
|
|
||||||
|
%mp_abort(iftrue=(&isgone = SASLibrary)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Library (&name) NOT deleted)
|
||||||
|
)
|
||||||
|
|
||||||
|
%put &sysmacroname: Library &name (&liburi) was successfully deleted;
|
||||||
|
|
||||||
|
%mend;
|
||||||
95
meta/mm_getfoldermembers.sas
Normal file
95
meta/mm_getfoldermembers.sas
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Returns all direct child members of a particular folder
|
||||||
|
@details Displays the children for a particular folder, in a similar fashion
|
||||||
|
to the viya counterpart (mv_getfoldermembers.sas)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
%mm_getfoldermembers(root=/, outds=rootfolders)
|
||||||
|
|
||||||
|
%mm_getfoldermembers(root=/User Folders/&sysuserid, outds=usercontent)
|
||||||
|
|
||||||
|
@param [in] root= the parent folder under which to return all contents
|
||||||
|
@param [out] outds= the dataset to create that contains the list of directories
|
||||||
|
@param [in] mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
|
<h4> Data Outputs </h4>
|
||||||
|
|
||||||
|
Example for `root=/`:
|
||||||
|
|
||||||
|
|metauri $17|metaname $256|metatype $32|
|
||||||
|
|---|---|---|
|
||||||
|
|A5XLSNXI.AA000001|Products |Folder|
|
||||||
|
|A5XLSNXI.AA000002|Shared Data |Folder|
|
||||||
|
|A5XLSNXI.AA000003|User Folders |Folder|
|
||||||
|
|A5XLSNXI.AA000004|System |Folder|
|
||||||
|
|A5XLSNXI.AA00003K|30.SASApps |Folder|
|
||||||
|
|A5XLSNXI.AA00006A|Public|Folder|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mm_getfoldertree.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
|
|
||||||
|
@version 9.4
|
||||||
|
@author Allan Bowe
|
||||||
|
|
||||||
|
**/
|
||||||
|
%macro mm_getfoldermembers(
|
||||||
|
root=
|
||||||
|
,outds=work.mm_getfoldertree
|
||||||
|
)/*/STORE SOURCE*/;
|
||||||
|
|
||||||
|
%if "&root" = "/" %then %do;
|
||||||
|
%local fname1 fname2 fname3;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
%let fname3=%mf_getuniquefileref();
|
||||||
|
data _null_ ;
|
||||||
|
file &fname1 ;
|
||||||
|
put '<GetMetadataObjects>' ;
|
||||||
|
put '<Reposid>$METAREPOSITORY</Reposid>' ;
|
||||||
|
put '<Type>Tree</Type>' ;
|
||||||
|
put '<NS>SAS</NS>' ;
|
||||||
|
put '<Flags>388</Flags>' ;
|
||||||
|
put '<Options>' ;
|
||||||
|
put '<XMLSelect search="Tree[SoftwareComponents/SoftwareComponent'@;
|
||||||
|
put '[@Name=''BIP Service'']]"/>';
|
||||||
|
put '</Options>' ;
|
||||||
|
put '</GetMetadataObjects>' ;
|
||||||
|
run ;
|
||||||
|
proc metadata in=&fname1 out=&fname2 verbose;run;
|
||||||
|
|
||||||
|
/* create an XML map to read the response */
|
||||||
|
data _null_;
|
||||||
|
file &fname3;
|
||||||
|
put '<SXLEMAP version="1.2" name="SASFolders">';
|
||||||
|
put '<TABLE name="SASFolders">';
|
||||||
|
put '<TABLE-PATH syntax="XPath">//Objects/Tree</TABLE-PATH>';
|
||||||
|
put '<COLUMN name="metauri">><LENGTH>17</LENGTH>';
|
||||||
|
put '<PATH syntax="XPath">//Objects/Tree/@Id</PATH></COLUMN>';
|
||||||
|
put '<COLUMN name="metaname"><LENGTH>256</LENGTH>>';
|
||||||
|
put '<PATH syntax="XPath">//Objects/Tree/@Name</PATH></COLUMN>';
|
||||||
|
put '</TABLE></SXLEMAP>';
|
||||||
|
run;
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 xml xmlfileref=&fname2 xmlmap=&fname3;
|
||||||
|
|
||||||
|
data &outds;
|
||||||
|
length metatype $32;
|
||||||
|
retain metatype 'Folder';
|
||||||
|
set &libref1..sasfolders;
|
||||||
|
run;
|
||||||
|
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
%mm_getfoldertree(root=&root, outds=&outds,depth=1)
|
||||||
|
data &outds;
|
||||||
|
set &outds(rename=(name=metaname publictype=metatype));
|
||||||
|
keep metaname metauri metatype;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
%mend;
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
/**
|
/**
|
||||||
@file mm_getfoldertree.sas
|
@file
|
||||||
@brief Returns all folders / subfolder content for a particular root
|
@brief Returns all folders / subfolder content for a particular root
|
||||||
@details Shows all members and SubTrees recursively for a particular root.
|
@details Shows all members and SubTrees recursively for a particular root.
|
||||||
Note - for big sites, this returns a lot of data! So you may wish to reduce
|
Note - for big sites, this returns a lot of data! So you may wish to reduce
|
||||||
the logging to speed up the process (see example below)
|
the logging to speed up the process (see example below), OR - use mm_tree.sas
|
||||||
|
which uses proc metadata and is far more efficient.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
options ps=max nonotes nosource;
|
options ps=max nonotes nosource;
|
||||||
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
||||||
options notes source;
|
options notes source;
|
||||||
|
|
||||||
@param root= the parent folder under which to return all contents
|
@param [in] root= the parent folder under which to return all contents
|
||||||
@param outds= the dataset to create that contains the list of directories
|
@param [out] outds= the dataset to create that contains the list of directories
|
||||||
@param mDebug= set to 1 to show debug messages in the log
|
@param [in] mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
<h4> SAS Macros </h4>
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ data &outds.TMP/view=&outds.TMP;
|
|||||||
__n1+1;
|
__n1+1;
|
||||||
/* Walk through all possible associations of this object. */
|
/* Walk through all possible associations of this object. */
|
||||||
__n2=1;
|
__n2=1;
|
||||||
if assoctype in ('Members','SubTrees') then
|
if assoctype in ('Members','SubTrees') then
|
||||||
do while(metadata_getnasn(pathuri,assoctype,__n2,metauri)>0);
|
do while(metadata_getnasn(pathuri,assoctype,__n2,metauri)>0);
|
||||||
__n2+1;
|
__n2+1;
|
||||||
call missing(name,publictype,MetadataUpdated,MetadataCreated);
|
call missing(name,publictype,MetadataUpdated,MetadataCreated);
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
@file mm_updatestpservertype.sas
|
@file
|
||||||
@brief Updates a type 2 stored process to run on STP or WKS context
|
@brief Updates a type 2 stored process to run on STP or WKS context
|
||||||
@details Only works on Type 2 (9.3 compatible) STPs
|
@details Only works on Type 2 (9.3 compatible) STPs
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%mm_updatestpservertype(target=/some/meta/path/myStoredProcess
|
%mm_updatestpservertype(target=/some/meta/path/myStoredProcess
|
||||||
,type=WKS)
|
,type=WKS)
|
||||||
|
|
||||||
<h4> SAS Macros </h4>
|
|
||||||
|
|
||||||
@param target= full path to the STP being deleted
|
@param target= full path to the STP being deleted
|
||||||
@param type= Either WKS or STP depending on whether Workspace or Stored Process
|
@param type= Either WKS or STP depending on whether Workspace or Stored Process
|
||||||
|
|||||||
@@ -6,31 +6,40 @@
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
%mm_updatestpsourcecode(stp=/my/metadata/path/mystpname
|
%mm_updatestpsourcecode(stp=/my/metadata/path/mystpname
|
||||||
,stpcode="/file/system/source.sas")
|
,stpcode="/file/system/source.sas")
|
||||||
|
|
||||||
|
@param [in] stp= the BIP Tree folder path plus Stored Process Name
|
||||||
@param stp= the BIP Tree folder path plus Stored Process Name
|
@param [in] stpcode= the source file (or fileref) containing the SAS code to load
|
||||||
@param stpcode= the source file (or fileref) containing the SAS code to load
|
|
||||||
into the stp. For multiple files, they should simply be concatenated first.
|
into the stp. For multiple files, they should simply be concatenated first.
|
||||||
@param minify= set to YES in order to strip comments, blank lines, and CRLFs.
|
@param [in] minify= set to YES in order to strip comments, blank lines, and CRLFs.
|
||||||
|
|
||||||
@param frefin= change default inref if it clashes with an existing one
|
@param frefin= deprecated - a unique fileref is now always used
|
||||||
@param frefout= change default outref if it clashes with an existing one
|
@param frefout= deprecated - a unique fileref is now always used
|
||||||
@param mDebug= set to 1 to show debug messages in the log
|
@param mDebug= set to 1 to show debug messages in the log
|
||||||
|
|
||||||
@version 9.3
|
@version 9.3
|
||||||
@author Allan Bowe
|
@author Allan Bowe
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
%macro mm_updatestpsourcecode(stp=
|
%macro mm_updatestpsourcecode(stp=
|
||||||
,stpcode=
|
,stpcode=
|
||||||
,minify=NO
|
,minify=NO
|
||||||
|
,mdebug=0
|
||||||
|
/* deprecated */
|
||||||
,frefin=inmeta
|
,frefin=inmeta
|
||||||
,frefout=outmeta
|
,frefout=outmeta
|
||||||
,mdebug=0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
%if &frefin ne inmeta or &frefout ne outmeta %then %do;
|
||||||
|
%put %str(WARN)ING: the frefin and frefout parameters will be deprecated in
|
||||||
|
an upcoming release.;
|
||||||
|
%end;
|
||||||
|
|
||||||
/* first, check if STP exists */
|
/* first, check if STP exists */
|
||||||
%local tsuri;
|
%local tsuri;
|
||||||
%let tsuri=stopifempty ;
|
%let tsuri=stopifempty ;
|
||||||
@@ -68,7 +77,9 @@ run;
|
|||||||
%return;
|
%return;
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
filename &frefin temp lrecl=32767;
|
%local frefin frefout;
|
||||||
|
%let frefin=%mf_getuniquefileref();
|
||||||
|
%let frefout=%mf_getuniquefileref();
|
||||||
|
|
||||||
/* write header XML */
|
/* write header XML */
|
||||||
data _null_;
|
data _null_;
|
||||||
@@ -81,7 +92,7 @@ run;
|
|||||||
/* write contents */
|
/* write contents */
|
||||||
%if %length(&stpcode)>2 %then %do;
|
%if %length(&stpcode)>2 %then %do;
|
||||||
data _null_;
|
data _null_;
|
||||||
file &frefin mod;
|
file &frefin lrecl=32767 mod;
|
||||||
infile &stpcode lrecl=32767;
|
infile &stpcode lrecl=32767;
|
||||||
length outstr $32767;
|
length outstr $32767;
|
||||||
input outstr ;
|
input outstr ;
|
||||||
@@ -110,9 +121,6 @@ data _null_;
|
|||||||
</UpdateMetadata>";
|
</UpdateMetadata>";
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
|
||||||
filename &frefout temp;
|
|
||||||
|
|
||||||
proc metadata in= &frefin out=&frefout;
|
proc metadata in= &frefin out=&frefout;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -124,5 +132,9 @@ run;
|
|||||||
put _infile_;
|
put _infile_;
|
||||||
run;
|
run;
|
||||||
%end;
|
%end;
|
||||||
|
%else %do;
|
||||||
|
filename &frefin clear;
|
||||||
|
filename &frefout clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
%mend;
|
%mend;
|
||||||
3404
package-lock.json
generated
3404
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sasjs/core",
|
"name": "@sasjs/core",
|
||||||
"description": "SAS Macro Library for Application Development",
|
"description": "Production Ready Macros for SAS Application Developers",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"SAS",
|
"SAS",
|
||||||
@@ -28,9 +28,10 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"docs": "./sasjs/utils/build.sh"
|
"docs": "sasjs doc && ./sasjs/utils/build.sh",
|
||||||
|
"postinstall": "node-git-hooks"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"@sasjs/cli": "^2.4.0"
|
"node-git-hooks": "^1.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,20 +14,20 @@ HIDE_SCOPE_NAMES = YES
|
|||||||
HIDE_UNDOC_CLASSES = YES
|
HIDE_UNDOC_CLASSES = YES
|
||||||
HIDE_UNDOC_MEMBERS = YES
|
HIDE_UNDOC_MEMBERS = YES
|
||||||
HTML_OUTPUT = $(DOXY_HTML_OUTPUT)
|
HTML_OUTPUT = $(DOXY_HTML_OUTPUT)
|
||||||
HTML_HEADER = $(DOXY_CONTENT)new_header.html
|
HTML_HEADER = $(HTML_HEADER)
|
||||||
HTML_FOOTER = $(DOXY_CONTENT)new_footer.html
|
HTML_EXTRA_FILES = $(HTML_EXTRA_FILES)
|
||||||
HTML_EXTRA_STYLESHEET = $(DOXY_CONTENT)new_stylesheet.css
|
HTML_FOOTER = $(HTML_FOOTER)
|
||||||
|
HTML_EXTRA_STYLESHEET = $(HTML_EXTRA_STYLESHEET)
|
||||||
INHERIT_DOCS = NO
|
INHERIT_DOCS = NO
|
||||||
INLINE_INFO = NO
|
INLINE_INFO = NO
|
||||||
INPUT = $(DOXY_CONTENT)../../README.md \
|
INPUT = $(DOXY_INPUT)
|
||||||
= $(DOXY_CONTENT)../../main.dox \
|
INPUT += main.dox
|
||||||
$(DOXY_INPUT)
|
LAYOUT_FILE = $(LAYOUT_FILE)
|
||||||
USE_MDFILE_AS_MAINPAGE = README.md
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
LAYOUT_FILE = $(DOXY_CONTENT)DoxygenLayout.xml
|
|
||||||
MAX_INITIALIZER_LINES = 0
|
MAX_INITIALIZER_LINES = 0
|
||||||
PROJECT_NAME = Macro Core
|
PROJECT_NAME = $(PROJECT_NAME)
|
||||||
PROJECT_LOGO = $(DOXY_CONTENT)Macro_core_website_1.png
|
PROJECT_LOGO = $(PROJECT_LOGO)
|
||||||
PROJECT_BRIEF = "Production Ready Macros for SAS Application Developers"
|
PROJECT_BRIEF = $(PROJECT_BRIEF)
|
||||||
RECURSIVE = YES
|
RECURSIVE = YES
|
||||||
REPEAT_BRIEF = NO
|
REPEAT_BRIEF = NO
|
||||||
SHOW_NAMESPACES = NO
|
SHOW_NAMESPACES = NO
|
||||||
@@ -38,4 +38,4 @@ STRICT_PROTO_MATCHING = YES
|
|||||||
STRIP_CODE_COMMENTS = NO
|
STRIP_CODE_COMMENTS = NO
|
||||||
SUBGROUPING = NO
|
SUBGROUPING = NO
|
||||||
TAB_SIZE = 2
|
TAB_SIZE = 2
|
||||||
VERBATIM_HEADERS = NO
|
VERBATIM_HEADERS = NO
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
ECHO on
|
|
||||||
|
|
||||||
rmdir /s /q C:\DEVELOPMENT\output
|
|
||||||
mkdir C:\DEVELOPMENT\output
|
|
||||||
|
|
||||||
doxygen.exe Doxyfile
|
|
||||||
26
sasjs/doxy/doxygen.svg
Normal file
26
sasjs/doxy/doxygen.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
sasjs/doxy/logo.png
Normal file
BIN
sasjs/doxy/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@@ -8,7 +8,7 @@
|
|||||||
<li class="footer">
|
<li class="footer">
|
||||||
$generatedby
|
$generatedby
|
||||||
<a href="https://www.doxygen.org/index.html">
|
<a href="https://www.doxygen.org/index.html">
|
||||||
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"
|
<img class="footer" src="$relpath^doxygen.svg" alt="doxygen"
|
||||||
/></a>
|
/></a>
|
||||||
$doxygenversion
|
$doxygenversion
|
||||||
</li>
|
</li>
|
||||||
@@ -24,9 +24,10 @@
|
|||||||
<address class="footer">
|
<address class="footer">
|
||||||
<small>
|
<small>
|
||||||
$generatedby  <a href="http://www.doxygen.org/index.html">
|
$generatedby  <a href="http://www.doxygen.org/index.html">
|
||||||
<img class="footer" src="$relpath^doxygen.png" alt="doxygen" />
|
<img class="footer" src="$relpath^doxygen.svg" alt="doxygen" />
|
||||||
</a>
|
</a>
|
||||||
$doxygenversion
|
$doxygenversion
|
||||||
</small>
|
</small>
|
||||||
</address>
|
</address>
|
||||||
|
|
||||||
<!--END !GENERATE_TREEVIEW-->
|
<!--END !GENERATE_TREEVIEW-->
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=9" />
|
<meta http-equiv="X-UA-Compatible" content="IE=9" />
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta name="author" content="Allan Bowe">
|
||||||
<meta name="generator" content="Doxygen $doxygenversion" />
|
<meta name="generator" content="Doxygen $doxygenversion" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<!--BEGIN PROJECT_NAME-->
|
<!--BEGIN PROJECT_NAME-->
|
||||||
<title>$projectname: $title</title>
|
<meta name="description" content="$projectbrief" />
|
||||||
<!--END PROJECT_NAME-->
|
<!--END PROJECT_NAME-->
|
||||||
<!--BEGIN !PROJECT_NAME-->
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
<title>$title</title>
|
<title>$title</title>
|
||||||
@@ -17,7 +19,7 @@
|
|||||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
$treeview $search $mathjax
|
$treeview $search $mathjax
|
||||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||||
<link rel="icon" href="https://sasjs.io/img/runningman.jpg" />
|
<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
|
||||||
$extrastylesheet
|
$extrastylesheet
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -31,52 +33,24 @@
|
|||||||
<tr style="height: 56px">
|
<tr style="height: 56px">
|
||||||
<!--BEGIN PROJECT_LOGO-->
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
<td id="projectlogo">
|
<td id="projectlogo">
|
||||||
<img alt="Logo" src="$relpath^$projectlogo" />
|
<a href="$relpath^"
|
||||||
|
><img alt="Logo" src="$relpath^$projectlogo"
|
||||||
|
/></a>
|
||||||
</td>
|
</td>
|
||||||
<!--END PROJECT_LOGO-->
|
<!--END PROJECT_LOGO-->
|
||||||
<!--BEGIN PROJECT_NAME-->
|
|
||||||
<td id="projectalign" style="padding-left: 0.5em">
|
<td id="projectalign" style="padding-left: 0.5em">
|
||||||
<div id="projectname">
|
|
||||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber"
|
|
||||||
>$projectnumber</span
|
|
||||||
><!--END PROJECT_NUMBER-->
|
|
||||||
</div>
|
|
||||||
<!--BEGIN PROJECT_BRIEF-->
|
|
||||||
<div id="projectbrief">
|
<div id="projectbrief">
|
||||||
Production Ready Macros for SAS Application Developers<br />
|
Production Ready Macros for SAS Application Developers<br />
|
||||||
<a href="https://github.com/sasjs/core">
|
<a href="https://github.com/sasjs/core">
|
||||||
https://github.com/sasjs/core
|
https://github.com/sasjs/core
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<meta name="Description" content="$projectbrief" />
|
|
||||||
<!--END PROJECT_BRIEF-->
|
|
||||||
</td>
|
</td>
|
||||||
<!--END PROJECT_NAME-->
|
|
||||||
<!--BEGIN !PROJECT_NAME-->
|
|
||||||
<!--BEGIN PROJECT_BRIEF-->
|
|
||||||
<td style="padding-left: 0.5em">
|
|
||||||
<div id="projectbrief">$projectbrief</div>
|
|
||||||
<table
|
|
||||||
style="padding-left: 2em"
|
|
||||||
cellspacing="0"
|
|
||||||
cellpadding="0"
|
|
||||||
>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
Production Ready Macros for SAS Application Developers
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="https://github.com/sasjs/core">
|
|
||||||
https://github.com/sasjs/core
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
<!--END PROJECT_BRIEF-->
|
|
||||||
<!--END !PROJECT_NAME-->
|
|
||||||
<!--BEGIN DISABLE_INDEX-->
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
<!--BEGIN SEARCHENGINE-->
|
<!--BEGIN SEARCHENGINE-->
|
||||||
<td>$searchbox</td>
|
<td>$searchbox</td>
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
|
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
|
||||||
"macroFolders": ["base", "meta", "metax", "viya", "lua"],
|
"macroFolders": ["base", "meta", "metax", "viya", "lua"],
|
||||||
"docConfig":{
|
"docConfig":{
|
||||||
"displayMacroCore": false
|
"displayMacroCore": false,
|
||||||
|
"enableLineage": false,
|
||||||
|
"doxyContent": {
|
||||||
|
"favIcon": "runningman.jpg",
|
||||||
|
"logo": "Macro_core_website_1.png",
|
||||||
|
"readMe": "../../README.md"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
####################################################################
|
####################################################################
|
||||||
# PROJECT: Macro Core Docs Build #
|
# PROJECT: Macro Core Docs Build #
|
||||||
|
# To execute, use the npm command (npm run docs) #
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
sasjs doc
|
|
||||||
|
|
||||||
# refresh github pages site
|
# refresh github pages site
|
||||||
rm -rf sasjsbuild/docsite
|
rm -rf sasjsbuild/docsite
|
||||||
git clone git@github.com:sasjs/core.github.io.git sasjsbuild/docsite
|
git clone git@github.com:sasjs/core.github.io.git sasjsbuild/docsite
|
||||||
|
|||||||
307
viya/mv_createjob.sas
Normal file
307
viya/mv_createjob.sas
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
/**
|
||||||
|
@file
|
||||||
|
@brief Creates a Viya Job
|
||||||
|
@details
|
||||||
|
Code is passed in as one or more filerefs.
|
||||||
|
|
||||||
|
%* Step 1 - compile macros ;
|
||||||
|
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
|
||||||
|
%inc mc;
|
||||||
|
|
||||||
|
%* Step 2 - Create some SAS code and add it to a job;
|
||||||
|
filename ft15f001 temp;
|
||||||
|
parmcards4;
|
||||||
|
data some_code;
|
||||||
|
set sashelp.class;
|
||||||
|
run;
|
||||||
|
;;;;
|
||||||
|
%mv_createjob(path=/Public/app/sasjstemp/jobs/myjobs,name=myjob)
|
||||||
|
|
||||||
|
The path to the job will then be shown in the log, eg as follows:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li mp_abort.sas
|
||||||
|
@li mv_createfolder.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getplatform.sas
|
||||||
|
@li mf_isblank.sas
|
||||||
|
@li mv_deletejes.sas
|
||||||
|
|
||||||
|
@param path= The full path (on SAS Drive) where the job will be created
|
||||||
|
@param name= The name of the job
|
||||||
|
@param desc= The description of the job
|
||||||
|
@param precode= Space separated list of filerefs, pointing to the code that
|
||||||
|
needs to be attached to the beginning of the job
|
||||||
|
@param code= Fileref(s) of the actual code to be added
|
||||||
|
@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 replace= select NO to avoid replacing any existing job in that location
|
||||||
|
@param contextname= Choose a specific context on which to run the Job. Leave
|
||||||
|
blank to use the default context. From Viya 3.5 it is possible to configure
|
||||||
|
a shared context - see
|
||||||
|
https://go.documentation.sas.com/?docsetId=calcontexts&docsetTarget=n1hjn8eobk5pyhn1wg3ja0drdl6h.htm&docsetVersion=3.5&locale=en
|
||||||
|
|
||||||
|
@version VIYA V.03.04
|
||||||
|
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro mv_createjob(path=
|
||||||
|
,name=
|
||||||
|
,desc=Created by the mv_createjob.sas macro
|
||||||
|
,precode=
|
||||||
|
,code=ft15f001
|
||||||
|
,access_token_var=ACCESS_TOKEN
|
||||||
|
,grant_type=sas_services
|
||||||
|
,replace=YES
|
||||||
|
,debug=0
|
||||||
|
,contextname=
|
||||||
|
);
|
||||||
|
%local oauth_bearer;
|
||||||
|
%if &grant_type=detect %then %do;
|
||||||
|
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
|
||||||
|
%else %let grant_type=sas_services;
|
||||||
|
%end;
|
||||||
|
%if &grant_type=sas_services %then %do;
|
||||||
|
%let oauth_bearer=oauth_bearer=sas_services;
|
||||||
|
%let &access_token_var=;
|
||||||
|
%end;
|
||||||
|
%put &sysmacroname: grant_type=&grant_type;
|
||||||
|
|
||||||
|
/* initial validation checking */
|
||||||
|
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
|
||||||
|
and &grant_type ne sas_services
|
||||||
|
)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Invalid value for grant_type: &grant_type)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%mf_isblank(&path)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(path value must be provided)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%length(&path)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(path value must be provided)
|
||||||
|
)
|
||||||
|
%mp_abort(iftrue=(%mf_isblank(&name)=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(name value must be provided)
|
||||||
|
)
|
||||||
|
|
||||||
|
options noquotelenmax;
|
||||||
|
|
||||||
|
* remove any trailing slash ;
|
||||||
|
%if "%substr(&path,%length(&path),1)" = "/" %then
|
||||||
|
%let path=%substr(&path,1,%length(&path)-1);
|
||||||
|
|
||||||
|
/* ensure folder exists */
|
||||||
|
%put &sysmacroname: Path &path being checked / created;
|
||||||
|
%mv_createfolder(path=&path)
|
||||||
|
|
||||||
|
%local base_uri; /* location of rest apis */
|
||||||
|
%let base_uri=%mf_getplatform(VIYARESTAPI);
|
||||||
|
|
||||||
|
/* fetching folder details for provided path */
|
||||||
|
%local fname1;
|
||||||
|
%let fname1=%mf_getuniquefileref();
|
||||||
|
proc http method='GET' out=&fname1 &oauth_bearer
|
||||||
|
url="&base_uri/folders/folders/@item?path=&path";
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
headers "Authorization"="Bearer &&&access_token_var";
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
%if &debug %then %do;
|
||||||
|
data _null_;
|
||||||
|
infile &fname1;
|
||||||
|
input;
|
||||||
|
putlog _infile_;
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* path exists. Grab follow on link to check members */
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 JSON fileref=&fname1;
|
||||||
|
|
||||||
|
data _null_;
|
||||||
|
set &libref1..links;
|
||||||
|
if rel='members' then call symputx('membercheck',quote("&base_uri"!!trim(href)),'l');
|
||||||
|
else if rel='self' then call symputx('parentFolderUri',href,'l');
|
||||||
|
run;
|
||||||
|
data _null_;
|
||||||
|
set &libref1..root;
|
||||||
|
call symputx('folderid',id,'l');
|
||||||
|
run;
|
||||||
|
%local fname2;
|
||||||
|
%let fname2=%mf_getuniquefileref();
|
||||||
|
proc http method='GET'
|
||||||
|
out=&fname2
|
||||||
|
&oauth_bearer
|
||||||
|
url=%unquote(%superq(membercheck));
|
||||||
|
headers
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
'Accept'='application/vnd.sas.collection+json'
|
||||||
|
'Accept-Language'='string';
|
||||||
|
%if &debug=1 %then %do;
|
||||||
|
debug level = 3;
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
/*data _null_;infile &fname2;input;putlog _infile_;run;*/
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 200)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
|
||||||
|
%if %upcase(&replace)=YES %then %do;
|
||||||
|
%mv_deletejes(path=&path, name=&name)
|
||||||
|
%end;
|
||||||
|
%else %do;
|
||||||
|
/* check that job does not already exist in that folder */
|
||||||
|
%local libref2;
|
||||||
|
%let libref2=%mf_getuniquelibref();
|
||||||
|
libname &libref2 JSON fileref=&fname2;
|
||||||
|
%local exists; %let exists=0;
|
||||||
|
data _null_;
|
||||||
|
set &libref2..items;
|
||||||
|
if contenttype='jobDefinition' and upcase(name)="%upcase(&name)" then
|
||||||
|
call symputx('exists',1,'l');
|
||||||
|
run;
|
||||||
|
%mp_abort(iftrue=(&exists=1)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(Job &name already exists in &path)
|
||||||
|
)
|
||||||
|
libname &libref2 clear;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* set up the body of the request to create the service */
|
||||||
|
%local fname3;
|
||||||
|
%let fname3=%mf_getuniquefileref();
|
||||||
|
data _null_;
|
||||||
|
file &fname3 TERMSTR=' ';
|
||||||
|
length string $32767;
|
||||||
|
string=cats('{"version": 0,"name":"'
|
||||||
|
,"&name"
|
||||||
|
,'","type":"Compute","parameters":[{"name":"_addjesbeginendmacros"'
|
||||||
|
,',"type":"CHARACTER","defaultValue":"false"}');
|
||||||
|
context=quote(cats(symget('contextname')));
|
||||||
|
if context ne '""' then do;
|
||||||
|
string=cats(string,',{"version": 1,"name": "_contextName","defaultValue":'
|
||||||
|
,context,',"type":"CHARACTER","label":"Context Name","required": false}');
|
||||||
|
end;
|
||||||
|
string=cats(string,'],"code":"');
|
||||||
|
put string;
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
/* insert the code, escaping double quotes and carriage returns */
|
||||||
|
%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_;
|
||||||
|
length filein 8 fileid 8;
|
||||||
|
filein = fopen("&fref","I",1,"B");
|
||||||
|
fileid = fopen("&fname3","A",1,"B");
|
||||||
|
rec = "20"x;
|
||||||
|
do while(fread(filein)=0);
|
||||||
|
rc = fget(filein,rec,1);
|
||||||
|
if rec='"' then do; /* DOUBLE QUOTE */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'"');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='0A'x then do; /* LF */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'n');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='0D'x then do; /* CR */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'r');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='09'x then do; /* TAB */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'t');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='5C'x then do; /* BACKSLASH */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else do;
|
||||||
|
rc =fput(fileid,rec);
|
||||||
|
rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
rc=fclose(filein);
|
||||||
|
rc=fclose(fileid);
|
||||||
|
run;
|
||||||
|
%end;
|
||||||
|
|
||||||
|
/* finish off the body of the code file loaded to JES */
|
||||||
|
data _null_;
|
||||||
|
file &fname3 mod TERMSTR=' ';
|
||||||
|
put '"}';
|
||||||
|
run;
|
||||||
|
|
||||||
|
/* now we can create the job!! */
|
||||||
|
%local fname4;
|
||||||
|
%let fname4=%mf_getuniquefileref();
|
||||||
|
proc http method='POST'
|
||||||
|
in=&fname3
|
||||||
|
out=&fname4
|
||||||
|
&oauth_bearer
|
||||||
|
url="&base_uri/jobDefinitions/definitions?parentFolderUri=&parentFolderUri";
|
||||||
|
headers 'Content-Type'='application/vnd.sas.job.definition+json'
|
||||||
|
%if &grant_type=authorization_code %then %do;
|
||||||
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
|
%end;
|
||||||
|
"Accept"="application/vnd.sas.job.definition+json";
|
||||||
|
%if &debug=1 %then %do;
|
||||||
|
debug level = 3;
|
||||||
|
%end;
|
||||||
|
run;
|
||||||
|
/*data _null_;infile &fname4;input;putlog _infile_;run;*/
|
||||||
|
%mp_abort(iftrue=(&SYS_PROCHTTP_STATUS_CODE ne 201)
|
||||||
|
,mac=&sysmacroname
|
||||||
|
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
|
||||||
|
)
|
||||||
|
/* clear refs */
|
||||||
|
filename &fname1 clear;
|
||||||
|
filename &fname2 clear;
|
||||||
|
filename &fname3 clear;
|
||||||
|
filename &fname4 clear;
|
||||||
|
libname &libref1 clear;
|
||||||
|
|
||||||
|
/* get the url so we can give a helpful log message */
|
||||||
|
%local url;
|
||||||
|
data _null_;
|
||||||
|
if symexist('_baseurl') then do;
|
||||||
|
url=symget('_baseurl');
|
||||||
|
if subpad(url,length(url)-9,9)='SASStudio'
|
||||||
|
then url=substr(url,1,length(url)-11);
|
||||||
|
else url="&systcpiphostname";
|
||||||
|
end;
|
||||||
|
else url="&systcpiphostname";
|
||||||
|
call symputx('url',url);
|
||||||
|
run;
|
||||||
|
|
||||||
|
|
||||||
|
%put &sysmacroname: Job &name successfully created in &path;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
%put &sysmacroname: Check it out here:;
|
||||||
|
%put &sysmacroname:;%put;
|
||||||
|
%put &url/SASJobExecution?_PROGRAM=&path/&name;%put;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
%put &sysmacroname:;
|
||||||
|
|
||||||
|
%mend;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
@file mv_createwebservice.sas
|
@file
|
||||||
@brief Creates a JobExecution web service if it doesn't already exist
|
@brief Creates a JobExecution web service if it doesn't already exist
|
||||||
@details
|
@details
|
||||||
Code is passed in as one or more filerefs.
|
Code is passed in as one or more filerefs.
|
||||||
@@ -566,23 +566,23 @@ run;
|
|||||||
rec = "20"x;
|
rec = "20"x;
|
||||||
do while(fread(filein)=0);
|
do while(fread(filein)=0);
|
||||||
rc = fget(filein,rec,1);
|
rc = fget(filein,rec,1);
|
||||||
if rec='"' then do;
|
if rec='"' then do; /* DOUBLE QUOTE */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'"');rc =fwrite(fileid);
|
rc =fput(fileid,'"');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='0A'x then do;
|
else if rec='0A'x then do; /* LF */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
|
||||||
rc =fput(fileid,'r');rc =fwrite(fileid);
|
|
||||||
end;
|
|
||||||
else if rec='0D'x then do;
|
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'n');rc =fwrite(fileid);
|
rc =fput(fileid,'n');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='09'x then do;
|
else if rec='0D'x then do; /* CR */
|
||||||
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
|
rc =fput(fileid,'r');rc =fwrite(fileid);
|
||||||
|
end;
|
||||||
|
else if rec='09'x then do; /* TAB */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'t');rc =fwrite(fileid);
|
rc =fput(fileid,'t');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
else if rec='5C'x then do;
|
else if rec='5C'x then do; /* BACKSLASH */
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
rc =fput(fileid,'\');rc =fwrite(fileid);
|
rc =fput(fileid,'\');rc =fwrite(fileid);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -106,6 +106,8 @@
|
|||||||
@li sas_services - will use oauth_bearer=sas_services
|
@li sas_services - will use oauth_bearer=sas_services
|
||||||
@param [in] inds= The input dataset containing a list of jobs and parameters
|
@param [in] inds= The input dataset containing a list of jobs and parameters
|
||||||
@param [in] maxconcurrency= The max number of parallel jobs to run. Default=8.
|
@param [in] maxconcurrency= The max number of parallel jobs to run. Default=8.
|
||||||
|
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
||||||
|
succcessfully
|
||||||
@param [in] mdebug= set to 1 to enable DEBUG messages
|
@param [in] mdebug= set to 1 to enable DEBUG messages
|
||||||
@param [out] outds= The output dataset containing the results
|
@param [out] outds= The output dataset containing the results
|
||||||
@param [out] outref= The output fileref to which to append the log file(s).
|
@param [out] outref= The output fileref to which to append the log file(s).
|
||||||
@@ -129,6 +131,7 @@
|
|||||||
,access_token_var=ACCESS_TOKEN
|
,access_token_var=ACCESS_TOKEN
|
||||||
,grant_type=sas_services
|
,grant_type=sas_services
|
||||||
,outref=0
|
,outref=0
|
||||||
|
,raise_err=0
|
||||||
,mdebug=0
|
,mdebug=0
|
||||||
);
|
);
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
@@ -307,7 +310,8 @@ data;run;%let jdswaitfor=&syslast;
|
|||||||
%end;
|
%end;
|
||||||
%if &jid=&jcnt %then %do;
|
%if &jid=&jcnt %then %do;
|
||||||
/* we are at the end of the loop - time to see which jobs have finished */
|
/* we are at the end of the loop - time to see which jobs have finished */
|
||||||
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref)
|
%mv_jobwaitfor(ANY,inds=&jdsrunning,outds=&jdswaitfor,outref=&outref
|
||||||
|
,raise_err=&raise_err)
|
||||||
%local done;
|
%local done;
|
||||||
%let done=%mf_nobs(&jdswaitfor);
|
%let done=%mf_nobs(&jdswaitfor);
|
||||||
%if &done>0 %then %do;
|
%if &done>0 %then %do;
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
following format: `/jobExecution/jobs/&JOBID./state` and the corresponding
|
following format: `/jobExecution/jobs/&JOBID./state` and the corresponding
|
||||||
job name. The uri should be in a `uri` variable, and the job path/name
|
job name. The uri should be in a `uri` variable, and the job path/name
|
||||||
should be in a `_program` variable.
|
should be in a `_program` variable.
|
||||||
|
@param [in] raise_err=0 Set to 1 to raise SYSCC when a job does not complete
|
||||||
|
succcessfully
|
||||||
@param [out] outds= The output dataset containing the list of states by job
|
@param [out] outds= The output dataset containing the list of states by job
|
||||||
(default=work.mv_jobexecute)
|
(default=work.mv_jobexecute)
|
||||||
@param [out] outref= A fileref to which the spawned job logs should be appended.
|
@param [out] outref= A fileref to which the spawned job logs should be appended.
|
||||||
@@ -81,6 +83,7 @@
|
|||||||
@li mp_abort.sas
|
@li mp_abort.sas
|
||||||
@li mf_getplatform.sas
|
@li mf_getplatform.sas
|
||||||
@li mf_getuniquefileref.sas
|
@li mf_getuniquefileref.sas
|
||||||
|
@li mf_getuniquelibref.sas
|
||||||
@li mf_existvar.sas
|
@li mf_existvar.sas
|
||||||
@li mf_nobs.sas
|
@li mf_nobs.sas
|
||||||
@li mv_getjoblog.sas
|
@li mv_getjoblog.sas
|
||||||
@@ -93,6 +96,7 @@
|
|||||||
,inds=0
|
,inds=0
|
||||||
,outds=work.mv_jobwaitfor
|
,outds=work.mv_jobwaitfor
|
||||||
,outref=0
|
,outref=0
|
||||||
|
,raise_err=0
|
||||||
);
|
);
|
||||||
%local oauth_bearer;
|
%local oauth_bearer;
|
||||||
%if &grant_type=detect %then %do;
|
%if &grant_type=detect %then %do;
|
||||||
@@ -136,7 +140,7 @@ options noquotelenmax;
|
|||||||
data _null_;
|
data _null_;
|
||||||
length jobparams $32767;
|
length jobparams $32767;
|
||||||
set &inds end=last;
|
set &inds end=last;
|
||||||
call symputx(cats('joburi',_n_),substr(uri,1,55)!!'/state','l');
|
call symputx(cats('joburi',_n_),substr(uri,1,55),'l');
|
||||||
call symputx(cats('jobname',_n_),_program,'l');
|
call symputx(cats('jobname',_n_),_program,'l');
|
||||||
call symputx(cats('jobparams',_n_),jobparams,'l');
|
call symputx(cats('jobparams',_n_),jobparams,'l');
|
||||||
if last then call symputx('uricnt',_n_,'l');
|
if last then call symputx('uricnt',_n_,'l');
|
||||||
@@ -151,7 +155,7 @@ run;
|
|||||||
%let fname0=%mf_getuniquefileref();
|
%let fname0=%mf_getuniquefileref();
|
||||||
|
|
||||||
data &outds;
|
data &outds;
|
||||||
format _program uri $128. state $32. timestamp datetime19. jobparams $32767.;
|
format _program uri $128. state $32. stateDetails $32. timestamp datetime19. jobparams $32767.;
|
||||||
stop;
|
stop;
|
||||||
run;
|
run;
|
||||||
|
|
||||||
@@ -159,7 +163,7 @@ run;
|
|||||||
%do i=1 %to &uricnt;
|
%do i=1 %to &uricnt;
|
||||||
%if "&&joburi&i" ne "0" %then %do;
|
%if "&&joburi&i" ne "0" %then %do;
|
||||||
proc http method='GET' out=&fname0 &oauth_bearer url="&base_uri/&&joburi&i";
|
proc http method='GET' out=&fname0 &oauth_bearer url="&base_uri/&&joburi&i";
|
||||||
headers "Accept"="text/plain"
|
headers "Accept"="application/json"
|
||||||
%if &grant_type=authorization_code %then %do;
|
%if &grant_type=authorization_code %then %do;
|
||||||
"Authorization"="Bearer &&&access_token_var"
|
"Authorization"="Bearer &&&access_token_var"
|
||||||
%end; ;
|
%end; ;
|
||||||
@@ -173,12 +177,20 @@ run;
|
|||||||
%end;
|
%end;
|
||||||
|
|
||||||
%let status=notset;
|
%let status=notset;
|
||||||
|
|
||||||
|
%local libref1;
|
||||||
|
%let libref1=%mf_getuniquelibref();
|
||||||
|
libname &libref1 json fileref=&fname0;
|
||||||
|
|
||||||
data _null_;
|
data _null_;
|
||||||
infile &fname0;
|
length state stateDetails $32;
|
||||||
input;
|
set &libref1..root;
|
||||||
call symputx('status',_infile_,'l');
|
call symputx('status',state,'l');
|
||||||
|
call symputx('stateDetails',stateDetails,'l');
|
||||||
run;
|
run;
|
||||||
|
|
||||||
|
libname &libref1 clear;
|
||||||
|
|
||||||
%if &status=completed or &status=failed or &status=canceled %then %do;
|
%if &status=completed or &status=failed or &status=canceled %then %do;
|
||||||
%local plainuri;
|
%local plainuri;
|
||||||
%let plainuri=%substr(&&joburi&i,1,55);
|
%let plainuri=%substr(&&joburi&i,1,55);
|
||||||
@@ -187,6 +199,7 @@ run;
|
|||||||
_program="&&jobname&i",
|
_program="&&jobname&i",
|
||||||
uri="&plainuri",
|
uri="&plainuri",
|
||||||
state="&status",
|
state="&status",
|
||||||
|
stateDetails=symget("stateDetails"),
|
||||||
timestamp=datetime(),
|
timestamp=datetime(),
|
||||||
jobparams=symget("jobparams&i");
|
jobparams=symget("jobparams&i");
|
||||||
%let joburi&i=0; /* do not re-check */
|
%let joburi&i=0; /* do not re-check */
|
||||||
@@ -205,6 +218,16 @@ run;
|
|||||||
,msg=%str(status &status not expected!!)
|
,msg=%str(status &status not expected!!)
|
||||||
)
|
)
|
||||||
%end;
|
%end;
|
||||||
|
|
||||||
|
%if (&raise_err) %then %do;
|
||||||
|
%if (&status = canceled or &status = failed or %length(&stateDetails)>0) %then %do;
|
||||||
|
%if ("&stateDetails" = "%str(war)ning") %then %let SYSCC=4;
|
||||||
|
%else %let SYSCC=5;
|
||||||
|
%put %str(ERR)OR: Job &&jobname&i. did not complete successfully. &stateDetails;
|
||||||
|
%return;
|
||||||
|
%end;
|
||||||
|
%end;
|
||||||
|
|
||||||
%end;
|
%end;
|
||||||
%if &i=&uricnt %then %do;
|
%if &i=&uricnt %then %do;
|
||||||
%local goback;
|
%local goback;
|
||||||
|
|||||||
Reference in New Issue
Block a user