Compare commits

...

36 Commits

Author SHA1 Message Date
Bart Jablonski
62a14b4560 SAS Packages Framework, version 20230207
SAS Packages Framework, version 20230207

News:
- "Additional Content" feature added to the framework.

Changes in the framework related to the new feature:
- new macro `%loadPackageAddCnt()`,
- modifications in the `%generatePackage()` macro,
- new parameter in `%loadPackage()` and `%installPackage()` macros,
- new code added in loading test.

Fixes:
- IML Modules loader utility macro rewritten,
- bug fixes.

Documentation:
- documentation updated,
- spelling fixes.
2023-02-07 17:51:24 +01:00
Bart Jablonski
0bd2f6f2d8 SAS Packages Framework, version 20230112
SAS Packages Framework, version 20230112

In the `%generatePackage()` macro:
- A `packageGenerated` macrovariable added to packages metadata.It contains timestamp when the package was generated in the ISO8601 form (`YYYY-MM-DDThh:mm:ss`) The variable is from now on used the log output for headers in lading, help, preview, etc.
- Diagnostic messages for loading required packages extended.
- Help info updated for macros dedicated to CASL UDFs and IML modules loading.
- SHA256 hash digest for the package is calculated in two versions(types). Type `F` generates digest for whole package zip file. Type `C` generates digest for package zip file content. For developer convenience both digests are generated and displayed. Details are available in the [documentation](https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation).

The `%verifyPackage()` macro adjusted to new digest types. For the backward compatibility verification works also of packages generated with previous versions of SPF.

Documentation updated.
2023-01-12 17:23:22 +01:00
Bart Jablonski
e3c42e6441 Update README.md
spelling corrected
2023-01-12 14:42:36 +01:00
Bartosz Jablonski
8807a1560e SAS Packages Framework, version 20221215
SAS Packages Framework, version 20221215

Changes in the framework:
- Bug fix for `formats` and `proto` with cherry picking.

- Packages regenerated with the latest framework version:
  - SQLinDS [2.2.4]
  - DFA [0.5.4]
  - macroArray [1.0.4]
  - BasePlus [1.18.4]
  - GSM [0.20.4]
  - dynMacroArray [0.2.4]

- New macro `%bpPIPE()` in BasePlus package.

- Documentation updated.
2022-12-15 17:56:08 +01:00
Bart Jablonski
a282349c86 Update README.md 2022-12-14 12:12:53 +01:00
Bart Jablonski
6dc4f22103 Update in README.md
The "Workshop video for the User" got outdated.
2022-12-14 09:33:54 +01:00
Bart Jablonski
2fd23f5b35 SAS Packages Framework, version 20221212
SAS Packages Framework, version 20221212

- New type `CASLUDF` for CASL User Defined Functions added to the framework.
- If a package contains IML modules or CASL user defined functions additional utility macros for IML Modules and CASL UDFs are generated when package is loaded.
- Documentation updated.
- Minor bugfix.
2022-12-12 23:41:19 +01:00
Bartosz Jablonski
f3f4747df6 SAS Packages Framework, version 20221212
SAS Packages Framework, version 20221212

- New type `CASLUDF` for CASL User Defined Functions added to the framework.
- If a package contains IML modules or CASL user defined functions additional utility macros for IML Modules and CASL UDFs are generated when package is loaded.
- Documentation updated.
- Minor bugfix.
2022-12-12 23:39:33 +01:00
Bart Jablonski
edca6a8a8c SAS Packages Framework, version 20221125 2022-11-26 23:50:13 +01:00
Bartosz Jablonski
f59c2a4893 SAS Packages Framework, version 20221125
## SAS Packages Framework, version 20221125

---

### Changes in `%generatePackage()` macro:
- Bug fix on the edge between cherry picking feature and loading required packages.
- Documentation updated.

---

### The following packages were regenerated with the latest version of the SAS Packages Framework:
- BasePlus [1.17.3]
- DFA [0.5.3]
- dynMacroArray [0.2.3]
- GSM [0.20.3]
- macroArray [1.0.3]
- SQLinDS [2.2.3]
2022-11-26 23:49:20 +01:00
Bart Jablonski
b4314c03e3 SAS Packages Framework, version 20221121
## SAS Packages Framework, version 20221121

---

### New feature of "Cherry picking" added to the SAS Packages Framework.
Sometimes a package offers so many features that the number may be "overwhelming".
In such case only some of them may be selected for loading. Such process
is called a "cherry picking". The feature is provided by the `%loadPackage()` macro 
which uses a `cherryPick=` parameter (see description below).

For example, execution of the following code:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
 %loadPackage(BasePlus, cherryPick=rainCloudPlot getVars)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
results with loading only the `rainCloudPlot` and the `getVars` elements.
If several object types (e.g., a macro and a format) share the same name 
all will be loaded.


What is the trade-off?
- Since the cherry picking selects only a part of the package the `SYSloadedPackages` 
macrovariable is not updated with the package name.
- Dependencies i.e., packages from the `ReqPackages` list, are not loaded automatically, 
so they have to be loaded manually.
- The `%unloadPackage()` macro executed on such partially loaded package may issue 
some (irrelevant) warnings.

---

### Changes in `%loadPackage()` macro:
- New `cherryPick=` parameter added to the macro.
  As a value a *space separated* list of selected elements 
  of the package to be loaded into the SAS session is expected.
  Default value of an asterisk (`*`) means: "load all elements of the package".
  Empty list is equivalent to default.
- Documentation updated.

### Changes in `%generatePackage()` macro:
- Code adjustment for the cherry picking feature.
- Minor additional code refactoring.
- The `%ICEloadPackage()` macro does not support cherry picking.

---

### The following packages were regenerated with the latest version of the framework:
- BasePlus [1.17.2]
- DFA [0.5.2]
- dynMacroArray [0.2.2]
- GSM [0.20.2]
- macroArray [1.0.2]
- SQLinDS [2.2.2]
2022-11-21 14:30:47 +01:00
Bartosz Jablonski
3a824b4d8b SAS Packages Framework, version 20221121
## SAS Packages Framework, version 20221121

---

### New feature of "Cherry picking" added to the SAS Packages Framework.
Sometimes a package offers so many features that the number may be "overwhelming".
In such case only some of them may be selected for loading. Such process
is called a "cherry picking". The feature is provided by the `%loadPackage()` macro
which uses a `cherryPick=` parameter (see description below).

For example, execution of the following code:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
 %loadPackage(BasePlus, cherryPick=rainCloudPlot getVars)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
results with loading only the `rainCloudPlot` and the `getVars` elements.
If several object types (e.g., a macro and a format) share the same name
all will be loaded.

What is the trade-off?
- Since the cherry picking selects only a part of the package the `SYSloadedPackages`
macrovariable is not updated with the package name.
- Dependencies i.e., packages from the `ReqPackages` list, are not loaded automatically,
so they have to be loaded manually.
- The `%unloadPackage()` macro executed on such partially loaded package may issue
some (irrelevant) warnings.

---

### Changes in `%loadPackage()` macro:
- New `cherryPick=` parameter added to the macro.
  As a value a *space separated* list of selected elements
  of the package to be loaded into the SAS session is expected.
  Default value of an asterisk (`*`) means: "load all elements of the package".
  Empty list is equivalent to default.
- Documentation updated.

### Changes in `%generatePackage()` macro:
- Code adjustment for the cherry picking feature.
- Minor additional code refactoring.
- The `%ICEloadPackage()` macro does not support cherry picking.

---

### The following packages were regenerated with the latest version of the framework:
- BasePlus [1.17.2]
- DFA [0.5.2]
- dynMacroArray [0.2.2]
- GSM [0.20.2]
- macroArray [1.0.2]
- SQLinDS [2.2.2]
2022-11-21 14:25:56 +01:00
Bart Jablonski
ba4b5f8c32 Update README.md 2022-11-16 11:57:15 +01:00
Bart Jablonski
15e7d48adf Update README.md 2022-11-13 20:19:06 +01:00
Bart Jablonski
a5b4f117cc Update SPFinit.md 2022-11-13 20:17:43 +01:00
Bart Jablonski
b3ea02b7b0 Update HelloWorldPackage.md 2022-11-13 20:17:09 +01:00
Bart Jablonski
e4dfc6a863 SAS Packages Framework, ver. 20221112 2022-11-12 18:45:08 +01:00
Bart Jablonski
7d083e879c SAS Packages Framework, ver. 20221112 2022-11-12 18:29:29 +01:00
Bartosz Jablonski
35e6ff8d5e SAS Packages Framework, ver. 20221112
SAS Packages Framework, ver. 20221112

Changes in `%generatePackage()` macro:
- refactoring of package metadata extraction and metadata file preparation,
- in a package folder all subfolders which name starts with `!` are ignored in the package generation process,
- in a package folder all subfolders with unknown code types are ignored in the package generation process,
- bug fix in package version extraction for required package list,
- new test added to loading test,
- documentation updated.

---

The following packages were regenerated:
- BasePlus [1.17.1]
- DFA [0.5.1]
- dynMacroArray [0.2.1]
- GSM [0.20.1]
- macroArray [1.0.1]
- SQLinDS [2.2.1]
2022-11-12 17:27:00 +01:00
Bart Jablonski
5bd013c925 "Hello World" example tutorial
"Hello World" example tutorial.
2022-11-12 00:43:12 +01:00
Bart Jablonski
2ad317db01 Create HelloWorldPackage.md 2022-11-12 00:39:23 +01:00
Bartosz Jablonski
6c38872ee2 SAS Packages Framework, ver. 20221107
**SAS Packages Framework**, ver. 20221107

- Minor update on the `%generatePackage()` macro log look.
2022-11-07 10:45:29 +01:00
Bartosz Jablonski
d35ac328cc SAS Packages Framework, ver. 20221107
**SAS Packages Framework**, ver. 20221107

- Minor update on the `%generatePackage()` macro log look.
2022-11-07 10:42:30 +01:00
Bartosz Jablonski
e3a813b257 Link to recording from the SAS Explore 2022 conference: "A BasePlus Package for SAS"
Link to recording from the SAS Explore 2022 conference: "A BasePlus Package for SAS"
2022-11-01 17:43:31 +01:00
Bartosz Jablonski
67bd3abd58 SAS Packages Framework, ver. 20221022
**SAS Packages Framework**, ver. `20221022`

In the `%generatePackage()` macro additional quality checks for files of EXEC and CLEAN types were added.
Each EXEC file should have a CLEAN file counterpart and vice versa.
- If the number of EXECs and CLEANs differs but both are positive macro issues a Warning.
- If EXECs are positive but CLEANs are zero (or other way around) macro issues an Error!

Documentation updated.
2022-10-22 22:13:50 +02:00
Bart Jablonski (yabwon)
1968330049 SAS Packages Framework, version 20221002
**SAS Packages Framework**, version `20221002`

- Modifications in the `%installPackage()` macro it is allowed to call installation of packages with version number (if used with `mirror=0`), for example: `%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM)`,

- For the `%installPackage()` and in the `%loadPackageS()` macros the list of packages standardised before execution to the form `package1(ver1) package2(ver2) package3(ver3)`,

- Fix for directories "with spaces" for `%installPackage()`.

- Documentation updated.
2022-10-01 12:11:40 +02:00
Bart Jablonski (yabwon)
7e202f81ff SAS Packages Framework, version 20221001
**SAS Packages Framework**, version 20221001

Update in setting package version.
- Modified macros: `%loadPackage()` and `%generatePackage()`.
- The `major.minor.patch` approach is also accepted accepted. Now package version can be: `X`, `X.Y`, or `X.Y.Z`. Missing parts are treated as 0, e.g. 1 is equivalent with 1.0.0, 1.2 is 1.2.0, and .2 is 0.2.0.

Modification in path for mirror 0 in the `%installPackage()` macro, it is `https://github.com/SASPAC/` now.
2022-10-01 01:02:59 +02:00
Bart Jablonski (yabwon)
26d9c735fe **SAS Packages Framework**, version 20220930.
**SAS Packages Framework**, version 20220930.

- In `%installPackage()` macro:
  - New parameter  `version=`  added. Indicates which historical version of a package to install. Historical version are available only if `mirror=0` is set. Default value is null which means "install the latest".
  - New default value for `mirror` parameter set to 0
- New repository dedicated for SAS Packages created: the *SASPAC - SAS Packages Archive* introduced under: `https://github.com/SASPAC`. Each package has its own project with historical versions in it.
- Documentation updated.
2022-09-30 20:27:23 +02:00
Bart Jablonski (yabwon)
11c0b95d7e SAS Packages Framework, version 20220925, extension
SAS Packages Framework, version 20220925, extension

Features:
- For the purpose of easy use of the SPF with SASAUTOS, inside the `SPF` directory, a subdirectory `Macros`, containing each macro of the framework in separate `*.sas` file, was introduced.
- Documentation update.
2022-09-28 22:37:26 +02:00
Bart Jablonski (yabwon)
be89c6b9c6 SAS Packages Framework, version 20220925
**SAS Packages Framework**, version `20220925`

New parameter `mirror=` added to the `%installPackage()` macro.
The `mirror` indicates which web location for packages installation is used.
Value `1` indicates: `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main`
Value `2` indicates: `https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES`
Default value is `1`.
2022-09-25 19:11:55 +02:00
Bart Jablonski
17b1239087 Merge pull request #50 from beauweta/patch-1
Update baseplus.md
2022-08-30 19:16:32 +02:00
Bart Jablonski (yabwon)
bbba37d8eb The SAS Packages Framework, version 20220830:
The SAS Packages Framework, version 20220830:

- New metadata checks added for required SAS components and required SAS packages.
- New parameter `delTestWork` in `%generatePackage()` macro added. It indicates if `WORK` directories generated by user tests should be deleted, i.e. the (NO)WORKTERM option is set.
- Log aesthetics and readability improved in the `%generatePackages()` macro:
  - subtitles added in the log,
  - `stimer` turned off,
  - some notes turned off.
- Generation of table with tests results updated.
- Documentation updated.

Packages regenerated with the new version of SPF:
- BasePlus
- SQLinDS
- macroArray
- DFA
- dynMacroArray
- GSM
2022-08-30 18:56:26 +02:00
Bart Jablonski
6ccc07a5bb Add SAS Packages Framework to SAS
Initiative to add SAS Packages Framework to SAS Base/Viya
2022-05-31 21:53:53 +02:00
Bart Jablonski
b5e15bda11 Add SAS Packages Framework to SAS
Innitiative to *add* SAS Packages Framework *to* SAS Base/Viya
2022-05-31 21:50:58 +02:00
Bart Jablonski
160c1bc9d3 Add SAS Packages Framework to SAS
Innitiative to *add* SAS Packages Framework *to* SAS Base/Viya
2022-05-31 21:49:56 +02:00
beauweta
76297dc5d8 Update baseplus.md
Just rephrased a few sentences and fixed some typos. Cheers, Christian
2022-05-15 15:15:10 +12:00
32 changed files with 8041 additions and 472 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 - 2022 Bartosz Jablonski
Copyright (c) 2019 - 2023 Bartosz Jablonski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

160
README.md
View File

@@ -1,4 +1,4 @@
# SAS_PACKAGES - a SAS Packages Framework and Repository
# SAS_PACKAGES - a SAS Packages Framework
---
@@ -8,7 +8,13 @@ A **SAS package** is an automatically generated, single, stand alone *zip* file
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. **The latest version** of SPF is **`20220420`**.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages.
---
### Current version:
**The latest version** of SPF is **`20230207`**.
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
@@ -16,63 +22,128 @@ The documentation and more advance reading would be the [**`SAS(r) packages - th
Short description of the SAS Packages Framework macros can be found [here](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md "Short description of the SAS Packages Framework macros")
**Videos** (the newer the better):
### Recordings and Presentations:
Videos presenting the SPF and packages, from various conferences and meetups (the newer the better):
- ["SAS Packages: The Way to Share" - SAS Global Forum 2020 V.E.](https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s "SGF2020") (April 2020, ~20 minutes, general overview but with a bit obsolete technical details)
- ["SAS Packages: The Way to Share" - SaSensei International Dojo No. 1](https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s "SID no. 1") (April 2020, ~28 minutes, general overview but with a bit obsolete technical details)
- ["Co nowego z pakietami SAS?" - SAS dla Administratorów i Praktyków 2020](https://www.youtube.com/watch?v=mXuep2k48Z8&feature=youtu.be&t=0s "SASAiP2020") (October 2020, in Polish, ~41 minutes, general overview and technical details how to use SPF)
- ["SAS Packages - The Way to Share" - Boston Area SAS Users Group webinar](https://www.basug.org/videos?wix-vod-video-id=78067e61413d43d3a6951974b3bc3014&wix-vod-comp-id=comp-klv807gt "BASUG") (November 2020, ~59 minutes, general overview and technical details how to use SPF)
- ["My First SAS Package: A How-To" - SAS Global Forum 2021 V.E.](https://www.youtube.com/watch?v=hqexaQtGw88 "SGF2021") (May 20th 2021, ~30 minutes, technical workshop on how to create a package)
- ["Kod SASowy ukryty na widoku" - SAS dla Administratorów i Praktyków 2021](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s) (November 24th 2021, in Polish, ~34 minutes, technical presentation with details about the GSM package)
- ["A BasePlus Package for SAS" - SAS Explore 2022](https://communities.sas.com/t5/SAS-Explore-Presentations/A-BasePlus-Package-for-SAS/ta-p/838246 "SASexplore2022 communities.sas.com") (September 27th-29th 2022, ~28 minutes, technical presentation with details about the BasePlus package), alternative video at YouTube is [here](https://www.youtube.com/watch?v=-Poxkx5WfOQ "SASexplore2022 TouTube")
- ["SAS Packages - State of the Union" - SaSensei International Dojo No. 13](https://www.youtube.com/watch?v=1GEldZYQjj0&t=0s "SID no. 13") (November 10th 2022, ~50 minutes, general overview with the latest technical details)
---
### Initiative to add SAS Packages Framework to SAS Base/Viya:
A **SASware Ballot Idea** for adding *SAS Packages Framework* macros into Base SAS and Viya was submitted Friday, May 27th 2022. If you would like to support the idea visit this [communities.sas.com post](https://communities.sas.com/t5/SASware-Ballot-Ideas/Add-SAS-Packages-Framework-to-the-SAS-Base-Viya/idi-p/815508) and up vote the idea!
- [SAS Global Forum 2020 V.E.](https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s "SGF2020") (April 2020)
- [Sasensei International Dojo](https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s "SID no. 1") (April 2020)
- [SAS dla Administratorów i Praktyków 2020](https://www.youtube.com/watch?v=mXuep2k48Z8&feature=youtu.be&t=0s "SASAiP2020") (October 2020, in Polish)
- [Boston Area SAS Users Group webinar](https://www.basug.org/videos?wix-vod-video-id=78067e61413d43d3a6951974b3bc3014&wix-vod-comp-id=comp-klv807gt "BASUG") (November 2020)
- [SAS Global Forum 2021 V.E.](https://www.youtube.com/watch?v=hqexaQtGw88 "SGF2021") (May 20th, 2021)
---
### The User:
To use a package:
- Create a folder for your packages, under Windows OS family, e.g. `C:/SAS_PACKAGES` or under Linux/UNIX OS family, e.g. `/home/<username>/SAS_PACKAGES`.
The first step to use a package with the SAS Packages Framework:
- Create a folder for your packages, under Windows OS family e.g., `C:/SAS_PACKAGES` or under Linux/UNIX OS family e.g., `/home/<username>/SAS_PACKAGES`.
and then either:
- Download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
- Manually download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
- \[Optional\] Manually download the `<packageName>.zip` file into the local packages folder.
- and Execute:
```sas
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
%include packages(SPFinit.sas); /* enable the framework */
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
%include packages(SPFinit.sas); /* enable the framework */
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
%helpPackage(packageName) /* get help about the package */
%loadPackage(packageName) /* load the package content into the SAS session */
%helpPackage(packageName) /* get help about the package */
%loadPackage(packageName) /* load the package content into the SAS session */
```
or if you need it just for "one time" only Execute:
or if you need it just for "one time" only:
- Execute:
```sas
filename packages "%sysfunc(pathname(work))"; /* setup temporary directory for packages in the WORK */
filename packages "%sysfunc(pathname(work))"; /* setup WORK as temporary directory for packages */
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit; /* enable the framework */
%installPackage(packageName) /* install the package */
%installPackage(packageName) /* install a package */
%helpPackage(packageName) /* get help about the package */
%loadPackage(packageName) /* load the package content into the SAS session */
```
[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y) \[May 6th, 2020\] [a bit outdated but gives the idea how it works]
or do it pragmatically:
- Enable the framework [first time only]:
```sas
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit; /* enable the framework */
```
- Install the framework on your machine in the folder you created:
```sas
filename packages "<directory/containing/packages/>";
%installPackage(SPFinit) /* install the framework */
```
- And from now on run it like this:
```sas
filename packages "<directory/containing/packages/>";
%include packages(SPFinit.sas);
%installPackage(packageName) /* install a package */
%helpPackage(packageName) /* get help about the package */
%loadPackage(packageName) /* load the package content into the SAS session */
```
---
The "Workshop video for the User" got outdated (in general). Newer version is comming soon, in the mean time see some of the vedeos from the "Recordings and Presentations" section above.
(You can watch the workshop if you wish, link is working and some parts are still valid source of information e.g., "`ICE` loading" or "`disk` loading")
<s>[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y) \[May 6th, 2020\] [~86 minutes, outdated (installPackage macro was not there yet) but gives the idea how it works especially load, help, unload, ICEload, and other details]</s>
---
### The Developer:
To create your own package:
- Download (and use) the `SPFinit.sas` file (the SAS Packages Framework), the part of the framework required for *testing* is there too.
- See this ["Hello World" example tutorial.](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/HelloWorldPackage.md "Hello World")
- Read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article to learn more details.
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To") or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To")
- Download and use the `SPFinit.sas` file (the SAS Packages Framework), the part of the framework required for *testing* is there too.
The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parametera.
---
#### If you have any questions, suggestions, or ideas do not hesitate to contact me!
### If you have any questions, suggestions, or ideas do not hesitate to contact me!
---
### Updates worth mentioning:
**Update**\[February 7th, 2023\]**:** `ADDCNT` ** type for *additional content* feature and ** `%loadPackageAddCnt()` **macro added to the framework. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20230207 "Additional Content"))**.
**Update**\[December 12th, 2022\]**:** `CASLUDF` ** type for CASL user defined functions added to the framework. Utility macros for for loading content in proc IML and proc CAS added. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221212 "New Type and Utility macros"))**.
**Update**\[November 21st, 2022\]**:** `%loadPackage()` **macro allows Cherry Picking of content (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221121 "Cherry Picking"))**.
**Update**\[September 30th, 2022\]**:** **New dedicated repository:** *SASPAC - the SAS Packages Archive* **is available as new location for packages storage**. Location of SASPAC is: [`https://github.com/SASPAC`](https://github.com/SASPAC)
**Update**\[November 11th, 2021\]**:** `%extendPackagesFileref()` **macro is available**.
**Update**\[October 15th, 2020\]**:** `%previewPackage()` **macro is available**.
@@ -98,31 +169,35 @@ If you find the SPF useful **share info** about it or **give it a [star](https:/
---
## Available packages:
Currently the following packages are available (see the `./packages` directory):
- **SQLinDS**\[2.2\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
**(!)** For "backward compatibility"/historical point of view the following packages are available under the `./packages` directory.
**(!)** Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
Packages:
- **SQLinDS**\[2.2.4\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
```sas
data class;
set %SQL(select * from sashelp.class order by age);
run;
```
SHA256 digest for SQLinDS: 701B69BE71B99792803BCE7718ED486259310FFB92E6D77ED1BC029D9CC67B60
SHA256 digest for SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
- **MacroCore**\[1\], a macro library for SAS application developers. Over 100 macros for Base SAS, metadata, and Viya. Provided by the [SASjs framework](https://sasjs.io "SASjs framework").
[SQLinDS in SASPAC](https://github.com/SASPAC/sqlinds "SQLinDS in SASPAC")
SHA256 digest for MacroCore: A23C29529F3CE7D0C8BEE9545C5D22D5B5594907547374A5135B8E5A48D7687B
[Documentation for MacroCore](https://core.sasjs.io "Documentation for MacroCore")
- **DFA** (Dynamic Function Arrays)\[0.5.4\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
- **DFA** (Dynamic Function Arrays)\[0.5\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
SHA256 digest for DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388BBA704EA
SHA256 digest for DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
- **macroArray**\[1.0\], implementation of an array concept in a macrolanguage, e.g.
[DFA in SASPAC](https://github.com/SASPAC/dfa "DFA in SASPAC")
- **macroArray**\[1.0.4\], implementation of an array concept in a macrolanguage, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -141,12 +216,13 @@ SHA256 digest for DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388B
which = 1:H:2
);
```
SHA256 digest for macroArray: DF63B0E027827A82038F1C8422787A0BC569BA93104BA1778DB6DD088A5D255C
SHA256 digest for macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
[MacroArray in SASPAC](https://github.com/SASPAC/macroarray "MacroArray in SASPAC")
- **BasePlus**\[1.17\] adds a bunch of functionalities I am missing in BASE SAS, such as:
- **BasePlus**\[1.18.4\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```sas
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
@@ -163,22 +239,28 @@ format x bool.;
%rainCloudPlot(sashelp.cars,DriveTrain,Invoice)
%zipLibrary(sashelp,libOut=work)
%bpPIPE(ls -la ~/)
```
SHA256 digest for BasePlus: 619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD
SHA256 digest for BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
- **GSM** (Generate Secure Macros)\[0.20\], package allows
[BasePlus in SASPAC](https://github.com/SASPAC/baseplus "BasePlus in SASPAC")
- **GSM** (Generate Secure Macros)\[0.20.4\], package allows
to create secured macros stored in SAS Proc FCMP functions.
The dataset with functions can be shared between different operating systems
and allows to generate macros on site without showing their code.
SHA256 digest for GSM: E6E2A6214EE7DC6E06AA76916A68B216DD7665184E63CF2C01F487A038E71B09
SHA256 digest for GSM: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
[GSM in SASPAC](https://github.com/SASPAC/gsm "GSM in SASPAC")
SHA256 digest for dynMacroArray: 7DA9BFDED37C18C4FB5BD7579A81A4B2578EEEF1546D1A3AB5C80DE07C88A615
- **dynMacroArray**\[0.2.4\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
SHA256 digest for dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
### ======

View File

@@ -0,0 +1,147 @@
## The "Hello World" Package
---
This is a "Hello World" example on how to build your first package with help of the SAS Packages Framework.
We will generate a `HelloWorld` package.
Follow the step by step instruction below.
---
`Step 1.` Create a folder for the framework e.g.,
`/home/<myUserName>/SASpackages` or `C:/SASpackages`
`Step 2.` Run the following code to install The SAS Packages Framework
in the folder you created in the `Step 1.`
```sas
filename packages "<put/folder/from/the/step/one/here>";
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
%include SPFinit;
%installPackage(SPFinit)
```
Check out the *log* to verify if the `Step 2.` was successful.
If it was - then continue.
`Step 3.` Create a folder for the content of the package we will generate e.g.,
`/home/<myUserName>/HelloWorldPackage` or `C:/HelloWorldPackage`
`Step 4.` Inside the directory from the `Step 3.` create two sub-folders: `01_formats`
and `02_macros`. Remember to use *lower case letters* only!
`Step 5.` Inside the `01_formats` folder create a `helloworldformat.sas` file.
Remember to use lower case letters in the file name. Copy-paste below code
into that file:
```sas
/*** HELP START ***//*
This is a help info for the HelloWorldFormat. format
*//*** HELP END ***/
value HelloWorldFormat
1 = " Hello"
2 = " SAS"
3 = " Packages"
4 = " World"
other = "!"
;
```
`Step 6.` Inside the `02_macros` folder create a `helloworldmacro.sas` file.
Remember to use lower case letters in the file name. Copy-paste below code
into that file:
```sas
/*** HELP START ***//*
This is a help info for the helloWorldMacro() macro
*//*** HELP END ***/
%macro HelloWorldMacro(n);
data _null_;
do i = 1 to &n.;
put i HelloWorldFormat. @;
end;
run;
%mend HelloWorldMacro;
```
`Step 7.` Inside the directory from the `Step 3.` create a `description.sas` file.
Remember to use lower case letters in the file name. Copy-paste below text
into that file, adjust lines 5 and 6:
```txt
Type: Package
Package: helloWorld
Title: My Hello World SAS package.
Version: 1.0
Author: <myFirstname> <myLastname> (my@mail.com)
Maintainer: <myFirstname> <myLastname> (my@mail.com)
License: MIT
Encoding: UTF8
Required: "Base SAS Software"
DESCRIPTION START:
## My "Hello World" SAS package ##
The "Hello World" is my first SAS package and
for sure it will not be the last package one!
DESCRIPTION END:
```
`Step 8.` Execute the following code and check the log
to read the `%generatePackage()` macro help info.
```sas
%generatePackage()
```
`Step 9.` Execute the following code using the folder
from the `Step 3.` and check the log to see how
the process of package generation went.
```sas
%generatePackage(
filesLocation=<put/folder/from/the/step/three/here>
)
```
`Step 10.` See the information in the output window and in the log.
The `WARNING:[License] No license.sas file provided, default (MIT) licence file will be generated.` can be ignored.
`Step 11.` Check the directory from the `Step 3.` and look for the `helloworld.zip` package file.
---
`Step 12.` Start a new SAS session, run the following code, and investigate the log:
```sas
filename packages ("<put/folder/from/the/step/one/here>" "<put/folder/from/the/step/three/here>");
%include packages(SPFinit.sas);
%loadPackage(HelloWorld)
%HelloWorldMacro(7)
```
---
### Congratulations!! You've just created your first HelloWorld package.
Now you are ready to do smome more advanced work.
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article, available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To + Video") (video included) or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To"), describing the proces of a package creation with more advanced example and technical details.
- Go to "bare metal" and read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") - an article which contains all technical details on how the SAS Packages Framework works and how to use it (both as a develope and as a user).
---
The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parametera.
---

View File

@@ -0,0 +1,104 @@
/*+extendPackagesFileref+*/
/*** HELP START ***/
%macro extendPackagesFileref(
packages /* A valid fileref name,
when empty the "packages" value is used */
)/secure
/*** HELP END ***/
des = 'Macro to list directories pointed by "packages" fileref, version 20230207. Run %extendPackagesFileref(HELP) for help info.'
;
%if %QUPCASE(&packages.) = HELP %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put ###########################################################################################;
%put ### This is short help information for the `extendPackagesFileref` macro #;
%put #-----------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to list directories pointed by 'packages' fileref, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and embedded inside the zip. #;
%put # #;
%put # The `%nrstr(%%extendPackagesFileref())` macro lists directories pointed by #;
%put # the packages fileref. It allows to add new dierctories to packages folder list. #;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packages` *Optional.* A valid fileref name, when empty the "packages" is used. #;
%put # Use case: #;
%put # `%nrstr(%%extendPackagesFileref()).` #;
%put # #;
%put # When used as: `%nrstr(%%extendPackagesFileref(HELP))` it displays this help information. #;
%put # #;
%put #-----------------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ##############################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and adding #;
%put # new directory. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in one of "C:/SAS_PK1" or "C:/SAS_PK2" folders. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( filename packages ("D:/NEW_DIR" %%extendPackagesFileref()); %%* add new directory; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put ###########################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDextendPackagesFileref;
%end;
%if %superq(packages) = %then %let packages = packages;
%if %qsysfunc(pathname(&packages.)) ne %then
%do;
%if %qsubstr(%qsysfunc(pathname(&packages.)), 1, 1) = %str(%() %then
%do;
%local length;
%let length = %eval(%length(%qsysfunc(pathname(&packages.)))-2);
%unquote(%qsubstr(%qsysfunc(pathname(&packages.)), 2, &length.))
%end;
%else "%sysfunc(pathname(&packages.))";
%end;
%ENDextendPackagesFileref:
%mend extendPackagesFileref;
/* Examples:
filename packages "C:\";
%include packages(SPFinit.sas)
%extendPackagesFileref(HELP)
filename packages (%extendPackagesFileref() "D:\");
filename packages list;
filename packages clear;
filename packages "C:\";
filename packages ("D:\" %extendPackagesFileref());
filename packages list;
%put *%extendPackagesFileref()*;
*/

File diff suppressed because it is too large Load Diff

178
SPF/Macros/helppackage.sas Normal file
View File

@@ -0,0 +1,178 @@
/*+helpPackage+*/
/*** HELP START ***/
%macro helpPackage(
packageName /* name of a package,
e.g. myPackageFile.zip,
required and not null */
, helpKeyword /* phrase to search in help,
when empty prints description
"*" means print all help
"license" prints license */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
, source2 = /*source2*/ /* option to print out details,
null by default */
, zip = zip /* standard package is zip (lowcase),
e.g. %helpPackage(PiPackage,*)
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use helpPackage in the form:
%helpPackage(PiPackage, *, zip=disk, options=)
*/
)/secure
/*** HELP END ***/
des = 'Macro to get help about SAS package, version 20230207. Run %helpPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `helpPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to get help about SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and provided with #;
%put # a single `help.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%helpPackage())` macro prints in the SAS log help #;
%put # information about the package provided by the developer. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%helpPackage(myPackage)).` #;
%put # If empty displays this help information. #;
%put # #;
%put # 2. `helpKeyword` *Optional.* A phrase to search in help, #;
%put # - when empty prints description, #;
%put # - "*" means: print all help, #;
%put # - "license" prints the license. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
%put # default value: `LOWCASE_MEMNAME` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `zip=` Standard package is zip (lowcase), #;
%put # e.g. `%nrstr(%%helpPackage(PiPackage))`. #;
%put # If the zip is not available use a folder. #;
%put # Unpack data to "pipackage.disk" folder #;
%put # and use helpPackage in the following form: #;
%put # `%nrstr(%%helpPackage(PiPackage, ,zip=disk, options=))` #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ####################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofhelpPackage;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
ENCODING =
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%include &_PackageFileref_.(help.sas) / &source2.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp. msglevel = &msglevel_tmp.;
%ENDofhelpPackage:
%mend helpPackage;
/*
TODO:
- macro for testing available packages in the packages folder [DONE] checkout: %listPackages()
- add MD5(&packageName.) value hash instead "package" word in filenames [DONE]
*/
/* Macros to install SAS packages, version 20230207 */
/* A SAS package is a zip file containing a group of files
with SAS code (macros, functions, data steps generating
data, etc.) wrapped up together and %INCLUDEed by
a single load.sas file (also embedded inside the zip).
*/

View File

@@ -0,0 +1,503 @@
/*+installPackage+*/
/*** HELP START ***/
%macro installPackage(
packagesNames /* space separated list of packages names, without the zip extension */
, sourcePath = /* location of the package, e.g. "www.some.page/", mind the "/" at the end */
, mirror = 0 /* indicates which location for package source should be used */
, version = /* indicates which version of a package to install */
, replace = 1 /* 1 = replace if the package already exist, 0 = otherwise */
, URLuser = /* user name for the password protected URLs */
, URLpass = /* password for the password protected URLs */
, URLoptions = /* options for the `sourcePath` URLs */
, loadAddCnt=0 /* should the additional content be loaded?
default is 0 - means No, 1 means Yes */
)
/secure
minoperator
/*** HELP END ***/
des = 'Macro to install SAS package, version 20230207. Run %%installPackage() for help info.'
;
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put ##############################################################################################;
%put ### This is short help information for the `installPackage` macro #;
%put #--------------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to install SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and embedded inside the zip. #;
%put # #;
%put # The `%nrstr(%%installPackage())` macro installs the package zip #;
%put # in the packages folder. The process of installation is equivalent with #;
%put # manual downloading the package zip file into the packages folder. #;
%put # #;
%put # In case the packages fileref is a multi-directory one the first directory #;
%put # will be selected as a destination. #;
%put # #;
%put #--------------------------------------------------------------------------------------------#;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packagesNames` Space separated list of packages names _without_ #;
%put # the zip extension, e.g. myPackage1 myPackage2, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%installPackage(myPackage1 myPackage2))`. #;
%put # If empty displays this help information. #;
%put # If the package name is *SPFinit* or *SASPackagesFramework* #;
%put # then the framework itself is downloaded. #;
%put # #;
%put # - `sourcePath=` Location of the package, e.g. "www.some.web.page/" #;
%put # Mind the "/" at the end of the path! #;
%put # Current default location for packages is: #;
%put # `https://github.com/SASPAC/` #;
%put # Current default location for the framework is: #;
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/` #;
%put # #;
%put # - `mirror=` Indicates which web location for packages installation is used. #;
%put # Value `0` indicates: #;
%put # `https://github.com/SASPAC/` #;
%put # Value `1` indicates: #;
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main` #;
%put # Value `2` indicates: #;
%put # `https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES` #;
%put # Default value is `0`. #;
%put # #;
%put # - `version=` Indicates which historical version of a package to install. #;
%put # Historical version are available only if `mirror=0` is set. #;
%put # Default value is null which means "install the latest". #;
%put # When there are multiple packages to install version #;
%put # is scan sequentially. #;
%put # #;
%put # - `replace=` With default value of `1` it causes existing package file #;
%put # to be replaced by new downloaded file. #;
%put # #;
%put # - `URLuser=` A user name for the password protected URLs, no quotes needed. #;
%put # #;
%put # - `URLpass=` A password for the password protected URLs, no quotes needed. #;
%put # #;
%put # - `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS #;
%put # documentation for the further details. #;
%put # #;
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
%put # content. The option indicates if it should be loaded #;
%put # Default value of zero (`0`) means "No", one (`1`) #;
%put # means "Yes". Content is extracted into the **packages** fileref #;
%put # directory in `<packageName>_AdditionalContent` folder. #;
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
%put # #;
%put #--------------------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example #################################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #### Example #################################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the multiple packages from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; );
%put %nrstr( %%include packages(SPFinit.sas); );
%put ;
%put %nrstr( %%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM) );
%put %nrstr( %%loadPackageS(GSM, baseplus(1.17), macroarray(1.0), dfa(0.5)) );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put ##############################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofinstallPackage;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let stimer_tmp = %sysfunc(getoption(stimer));
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
/*
Reference:
https://blogs.sas.com/content/sasdummy/2011/06/17/how-to-use-sas-data-step-to-copy-a-file-from-anywhere/
*/
/* in case the 'packages' fileref is multi-directory the first directory will be selected as a destination */
data _null_;
if "(" =: pathname("packages") then
/* get the firstPackagesPath */
call symputX("firstPackagesPath", dequote(kscanx(pathname("packages"), 1, "()", "QS")), "L");
else
call symputX("firstPackagesPath", pathname("packages"), "L");
run;
%if %superq(sourcePath)= %then
%do;
%local SPFinitMirror;
/* the defaults are: */
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
%if 0 = %superq(mirror) %then
%do;
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
%let sourcePath = https://github.com/SASPAC/; /*usercontent*/
%goto mirrorEnd;
%end;
%if 1 = %superq(mirror) %then
%do;
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
%goto mirrorEnd;
%end;
%if 2 = %superq(mirror) %then
%do;
%let SPFinitMirror = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/SPF/SPFinit.sas;
%let sourcePath = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/packages/;
%goto mirrorEnd;
%end;
%mirrorEnd:
%put INFO: Source path is &sourcePath.;
%end;
%else
%do;
%let mirror=-1;
%let SPFinitMirror = &sourcePath.SPFinit.sas;
%end;
%local i str;
/* standardise list of packages */
%let str = %qsysfunc(compress(%superq(packagesNames),[{(. _)}],kad));
%let str = %qsysfunc(translate(%superq(str),[[]],{()}));
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
%let str = %qsysfunc(compbl(%superq(str)));
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
%let str = %unquote(&str.);
%let packagesNames = %qsysfunc(translate(%superq(str),(),[]));
%if %length("%sysfunc(compress(%superq(str),[,k))") NE %length("%sysfunc(compress(%superq(str),],k))") %then
%do;
%put ERROR: Syntax error in list of packages!;
%put ERROR- %superq(packagesNames);
%goto packagesListError;
%end;
%put ;
%put INFO: Calling: &packagesNames.;
%do i = 1 %to %sysfunc(countw(&packagesNames., , S));
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
%local packageName packageSubDir vers versA versB;
%put ;
/*%put ### %scan(&packagesNames., &i., , S) ###;*/
%let packageName = %scan(%scan(&packagesNames., &i., , S),1,{[()]});
%let versA = %scan(%scan(&packagesNames., &i., , S),2,{[()]});
%let versB = %scan(&version., &i., , S);
%let vers=;
%if %superq(versB) ne %then %let vers = &versB.;
%if %superq(versA) ne %then %let vers = &versA.;
%if -1 = &mirror %then /* ignore version when direct path is provided */
%do;
%let vers=;
%end;
%put ### &packageName.(&vers.) ###;
%put *** %lowcase(&packageName.) start *****************************************;
%local in out _IOFileref_;
data _null_; call symputX("_IOFileref_", put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
%let in = i&_IOFileref_.;
%let out = o&_IOFileref_.;
/* %let in = i%sysfunc(md5(&packageName.),hex7.); */
/* %let out = o%sysfunc(md5(&packageName.),hex7.); */
/*options MSGLEVEL=i;*/
%if %upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK) %then
%do;
/* allows to install/download the framework file like any other package */
%if %superq(mirror) in (0 1) AND (%superq(vers) ne) %then
%do;
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/&vers./SPF/SPFinit.sas;
%end;
filename &in URL
"&SPFinitMirror."
recfm=N lrecl=1;
filename &out
"&firstPackagesPath./SPFinit.sas"
recfm=N lrecl=1;
%end;
%else
%do;
%if 0 = %superq(mirror) %then
%do;
%let packageSubDir = %lowcase(&packageName.)/raw/main/;
%if %superq(vers) ne %then
%do;
/*%let packageSubDir = %lowcase(&packageName.)/main/hist/&version./;*/
%let packageSubDir = %lowcase(&packageName.)/raw/&vers./;
%end;
%end;
filename &in URL "&sourcePath.&packageSubDir.%lowcase(&packageName.).zip"
%if (%superq(URLuser) ne ) %then
%do;
user = "&URLuser."
pass = "&URLuser."
%end;
&URLoptions.
recfm=N lrecl=1;
filename &out "&firstPackagesPath./%lowcase(&packageName.).zip" recfm=N lrecl=1;
%end;
/*
filename in list;
filename out list;
*/
/* copy the file byte-by-byte */
%local installationRC;
%let installationRC=1;
data _null_;
length filein 8 out_path in_path $ 4096;
out_path = pathname ("&out");
in_path = pathname ("&in" );
filein = fopen( "&in", 'S', 1, 'B');
if filein = 0 then
put "ERROR: Source file:" /
"ERROR- " in_path /
"ERROR- is unavailable!";
if filein > 0;
put @2 "Source information:";
infonum = FOPTNUM(filein);
length infoname $ 32 infoval $ 128;
do i=1 to coalesce(infonum, -1);
infoname = FOPTNAME(filein, i);
infoval = FINFO(filein, infoname);
put @4 infoname ":"
/ @6 infoval
;
end;
rc = FCLOSE(filein);
put;
if FEXIST("&out") = 0 then
do;
put @2 "Installing the &packageName. package"
/ @2 "in the &firstPackagesPath. directory.";
rc = FCOPY("&in", "&out");
end;
else if FEXIST("&out") = 1 then
do;
if symgetn("replace")=1 then
do;
put @2 "The following file will be replaced during "
/ @2 "installation of the &packageName. package: "
/ @5 out_path;
rc = FDELETE("&out");
rc = FCOPY("&in", "&out");
end;
else
do;
put @2 "The following file will NOT be replaced: "
/ @5 out_path;
rc = 1;
end;
end;
put @2 "Done with return code " rc= "(zero = success)";
call symputX("installationRC", rc, "L");
run;
filename &in clear;
filename &out clear;
%if 1 = &loadAddCnt.
AND 0 = &installationRC.
AND NOT (%upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK))
%then
%do;
%put; %put - Additional content loading - Start -;
%loadPackageAddCnt(&packageName.
,path=&firstPackagesPath.
,target=&firstPackagesPath.
)
%put - Additional content loading - End -;
%end;
%put *** %lowcase(&packageName.) end *******************************************;
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
%end;
%packagesListError:
options ls = &ls_tmp. ps = &ps_tmp.
&notes_tmp. &source_tmp.
&stimer_tmp. &fullstimer_tmp.
msglevel=&msglevel_tmp.;
%ENDofinstallPackage:
%mend installPackage;
/*** HELP START ***/
/*
Filenames references "packages" and "package" are reserved keywords.
The first one should be used to point local folder with packages.
The second is used internally by macros.
Do not use them otherwise than:
filename packages "</the/folder/with/sas/packages>";
since it may affect stability of the framework.
**/
/* Example 1: Enabling the SAS Package Framework
and loading the SQLinDS package from the local directory.
Assume that the SPFinit.sas file and the SQLinDS
package (sqlinds.zip file) are located in
the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%helpPackage(SQLinDS) %* get help about the package;
%loadPackage(SQLinDS) %* load the package content into the SAS session;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
*/
/* Example 2: Enabling the SAS Package Framework
from the local directory and installing & loading
the SQLinDS package from the Internet.
Assume that the SPFinit.sas file
is located in the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%installPackage(SQLinDS) %* install the package from the Internet;
%helpPackage(SQLinDS) %* get help about the package;
%loadPackage(SQLinDS) %* load the package content into the SAS session;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
*/
/* Example 3: Enabling the SAS Package Framework
and installing & loading the SQLinDS package
from the Internet.
Run the following code in your SAS session:
filename packages "%sysfunc(pathname(work))"; %* setup WORK as a temporary directory for packages;
filename spfinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPFinit.sas";
%include spfinit; %* enable the framework;
%installPackage(SQLinDS) %* install the package from the Internet;
%helpPackage(SQLinDS) %* get help about the package;
%loadPackage(SQLinDS) %* load the package content into the SAS session;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
*/
/* Example 4:
Assume that the SPFinit.sas file and the SQLinDS package (sqlinds.zip file)
are located in the "C:/SAS_PACKAGES/" folder.
In case when user SAS session does not support ZIP fileref
the following solution could be used.
Unzip the packagename.zip content into the packagename.disk folder
and run macros with the following options: ;
%loadPackage(packageName,zip=disk,options=)
%helpPackage(packageName,,zip=disk,options=) %* mind the double comma!! ;
%unloadPackage(packageName,zip=disk,options=)
*/
/* Example 5: Enabling the SAS Package Framework from the local directory
and installing the SQLinDS package from the Internet.
Assume that the SPFinit.sas file is located in
the "C:/SAS_PACKAGES/" folder.
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%installPackage(SQLinDS); %* install package;
%installPackage(SQLinDS); %* overwrite already installed package;
%installPackage(SQLinDS,replace=0); %* prevent overwrite installed package;
%installPackage(NotExistingPackage); %* handling with not existing package;
*/
/*** HELP END ***/
/*** HELP START ***/
/* Macro to list SAS packages in packages folder.
Version 20230207
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
data, etc.) wrapped up together and %INCLUDEed by
a single load.sas file (also embedded inside the zip).
*/
/*
* Example 1: Set local packages directory, enable the framework,
and list packages in the local repository.
filename packages "C:\SAS_PACKAGES";
%include packages(SPFinit.sas);
%listPackages()
*/
/*** HELP END ***/

180
SPF/Macros/listpackages.sas Normal file
View File

@@ -0,0 +1,180 @@
/*+listPackages+*/
%macro listPackages()/secure PARMBUFF
des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HELP) for help, version 20230207.'
;
%if %QUPCASE(&SYSPBUFF.) = %str(%(HELP%)) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put ###########################################################################################;
%put ### This is short help information for the `listPackages` macro #;
%put #-----------------------------------------------------------------------------------------#;;
%put # #;
%put # Macro to list available SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and embedded inside the zip. #;
%put # #;
%put # The `%nrstr(%%listPackages())` macro lists packages available #;
%put # in the packages folder. List is printed inthe SAS Log. #;
%put # #;
%put #### Parameters: #;
%put # #;
%put # NO PARAMETERS #;
%put # #;
%put # When used as: `%nrstr(%%listPackages(HELP))` it displays this help information. #;
%put # #;
%put #-----------------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ##############################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and listing #;
%put # available packages. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%listPackages() %%* list available packages; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put ###########################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDoflistPackages;
%end;
%local ls_tmp ps_tmp notes_tmp source_tmp filesWithCodes;
%let filesWithCodes = WORK._%sysfunc(datetime(), hex16.)_;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
options NOnotes NOsource ls=MAX ps=MAX;
data _null_;
length baseAll $ 32767;
baseAll = pathname("packages");
if baseAll = " " then
do;
put "NOTE: The file reference PACKAGES is not assigned.";
stop;
end;
if char(baseAll,1) ^= "(" then baseAll = quote(strip(baseAll)); /* for paths with spaces */
do k = 1 to kcountw(baseAll, "()", "QS"); drop k;
base = dequote(kscanx(baseAll, k, "()", "QS"));
length folder $ 64 file $ 1024 folderRef fileRef $ 8;
folderRef = "_%sysfunc(datetime(), hex6.)0";
rc=filename(folderRef, base);
folderid=dopen(folderRef);
putlog " ";
put "/*" 100*"+" ;
do i=1 to dnum(folderId); drop i;
if i = 1 then
do;
put " #";
put " # Listing packages for: " base;
put " #";
end;
folder = dread(folderId, i);
fileRef = "_%sysfunc(datetime(), hex6.)1";
rc = filename(fileRef, catx("/", base, folder));
fileId = dopen(fileRef);
EOF = 0;
if fileId = 0 and lowcase(kscanx(folder, -1, ".")) = 'zip' then
do;
file = catx('/',base, folder);
rc1 = filename("package", strip(file), 'zip', 'member="description.sas"');
rcE = fexist("package");
rc2 = filename("package", " ");
if rcE then /* if the description.sas exists in the zip then read it */
do;
putlog " * ";
length nn $ 96;
if (96-lengthn(file)) < 1 then
put " * " file;
else
do;
nn = repeat("*", (96-lengthn(file)));
put " * " file nn;
end;
infile _DUMMY_ ZIP FILEVAR=file member="description.sas" end=EOF;
do until(EOF);
input;
if strip(upcase(kscanx(_INFILE_,1,":"))) in ("PACKAGE" "TITLE" "VERSION" "AUTHOR" "MAINTAINER" "LICENSE") then
do;
_INFILE_ = kscanx(_INFILE_,1,":") !! ":" !! kscanx(_INFILE_,2,":");
putlog " * " _INFILE_;
end;
if strip(upcase(strip(_INFILE_))) =: "DESCRIPTION START:" then leave;
end;
end;
end;
rc = dclose(fileId);
rc = filename(fileRef);
end;
putlog " * ";
put 100*"+" "*/";
rc = dclose(folderid);
rc = filename(folderRef);
end;
stop;
run;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
%ENDoflistPackages:
%mend listPackages;
/*** HELP START ***/
/* Macro to generate SAS packages.
Version 20230207
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
data, etc.) wrapped up together and %INCLUDEed by
a single load.sas file (also embedded inside the zip).
See examples below.
*/
/*** HELP END ***/

275
SPF/Macros/loadpackage.sas Normal file
View File

@@ -0,0 +1,275 @@
/*+loadPackage+*/
/*** HELP START ***/
%macro loadPackage(
packageName /* name of a package,
e.g. myPackage,
required and not null */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
, source2 = /*source2*/ /* option to print out details,
null by default */
, requiredVersion = . /* option to test if loaded package
is provided in required version */
, lazyData = /* a list of names of lazy datasets
to be loaded, if not null then
datasets from the list are loaded
instead of a package, asterisk
means "load all datasets" */
, zip = zip /* standard package is zip (lowcase),
e.g. %loadPackage(PiPackage)
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use loadPackage in the form:
%loadPackage(PiPackage, zip=disk, options=)
*/
, cherryPick=* /* space separated list of selected elements of the package
to be loaded into the session, default value "*" means
"load all elements of the package"
*/
, loadAddCnt=0 /* should the additional content be loaded?
default is 0 - means No, 1 means Yes */
)/secure
/*** HELP END ***/
des = 'Macro to load SAS package, version 20230207. Run %loadPackage() for help info.'
minoperator
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `loadPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to *load* SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and included by #;
%put # a single `load.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%loadPackage())` macro loads package content, i.e. macros, #;
%put # functions, formats, etc., from the zip into the SAS session. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%loadPackage(myPackage)).` #;
%put # If empty displays this help information. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
%put # default value: `LOWCASE_MEMNAME` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
%put # package is provided in required version, #;
%put # default value: `.` #;
%put # #;
%put # - `lazyData=` *Optional.* A space separated list of names of lazy #;
%put # datasets to be loaded. If not null datasets from the #;
%put # list are loaded instead of the package. #;
%put # An asterisk (*) means *load all lazy datasets*. #;
%put # #;
%put # - `zip=` *Optional.* Standard package is zip (lowcase), #;
%put # e.g. `%nrstr(%%loadPackage(PiPackage))`. #;
%put # If the zip is not available use a folder. #;
%put # Unpack data to "pipackage.disk" folder #;
%put # and use loadPackage in the following form: #;
%put # `%nrstr(%%loadPackage(PiPackage, zip=disk, options=))` #;
%put # #;
%put # - `cherryPick=` *Optional.* A space separated list of selected elements #;
%put # of the package to be loaded into the SAS session. #;
%put # Default value of an asterisk (*) means: #;
%put # "load all elements of the package". #;
%put # #;
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
%put # content. The option indicates if it should be loaded #;
%put # Default value of zero (`0`) means "No", one (`1`) #;
%put # means "Yes". Content is extracted into the **Work** #;
%put # directory in `<packageName>_AdditionalContent` folder. #;
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put ### Example 1 ###################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put # #;
%put ### Example 2 ###################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & cherry picking #;
%put # elements of the BasePlus package. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(BasePlus) %%* install the package from the Internet; );
%put %nrstr( %%loadPackage(BasePlus, cherryPick=getVars) %%* cherry pick the content; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put # #;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofloadPackage;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let stimer_tmp = %sysfunc(getoption(stimer));
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
/* convert cherryPick to lower case if needed */
%if NOT (%str(*) = %superq(cherryPick)) %then
%do;
data _null_;
call symputX("cherryPick",lowcase(compbl(compress(symget("cherryPick"),". _","KDA"))),"L");
run;
%end;
/* empty list is equivalent to "*" */
%if %superq(cherryPick)= %then
%do;
%let cherryPick=*;
%end;
%if %superq(loadAddCnt) NE 1 %then
%do;
%let loadAddCnt = 0;
%end;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
/* test if required version of package is "good enough" */
%local rV pV;
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
+ (%scan(&pV.,2,.,M)+0)*1e4
+ (%scan(&pV.,3,.,M)+0)*1e0);
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
+ (%scan(&rV.,2,.,M)+0)*1e4
+ (%scan(&rV.,3,.,M)+0)*1e0);
%if %sysevalf(&rV. > &pV.) %then
%do;
%put ERROR: Package &packageName. will not be loaded!;
%put ERROR- Required version is &requiredVersion.;
%put ERROR- Provided version is &packageVersion.;
%put ERROR- Verify installed version of the package.;
%put ERROR- ;
%GOTO WrongVersionOFPackage; /*%RETURN;*/
%end;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
ENCODING =
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%if %superq(lazyData) = %then
%do;
%local tempLoad_minoperator;
%let tempLoad_minoperator = %sysfunc(getoption(minoperator));
options minoperator; /* MinOperator option is required for cherryPicking to work */
%include &_PackageFileref_.(load.sas) / &source2.;
options &tempLoad_minoperator.;
%if 1 = &loadAddCnt. %then
%do;
%put; %put - Additional content loading - Start -;
%loadPackageAddCnt(&packageName.,
path=&path.)
%put - Additional content loading - End -;
%end;
%end;
%else
%do;
%include &_PackageFileref_.(lazydata.sas) / &source2.;
%end;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
%WrongVersionOFPackage:
/* restore optionos */
options ls = &ls_tmp. ps = &ps_tmp.
&notes_tmp. &source_tmp.
&stimer_tmp. &fullstimer_tmp.
msglevel=&msglevel_tmp.;
%ENDofloadPackage:
%mend loadPackage;

View File

@@ -0,0 +1,365 @@
/*+loadPackageAddCnt+*/
/*** HELP START ***/
%macro loadPackageAddCnt(
packageName /* name of a package,
e.g. myPackage,
required and not null */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, target = %sysfunc(pathname(WORK)) /* a path in which the directory with
additional content will be generated,
name of directory created is set to
`&packageName._AdditionalContent`
default location is SAS work */
, source2 = /*source2*/ /* option to print out details,
null by default */
, requiredVersion = . /* option to test if loaded package
is provided in required version */
)/secure
/*** HELP END ***/
des = 'Macro to load additional content for a SAS package, version 20230207. Run %loadPackageAddCnt() for help info.'
minoperator
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `loadPackageAddCnt` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to *load* additional content for a SAS package, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and included by #;
%put # a single `load.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%loadPackageAddCnt())` macro loads additional content #;
%put # for a package (of course only if one is provided). #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%loadPackageAddCnt(myPackage))`. #;
%put # If empty displays this help information. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `target=` *Optional.* Location where the directory with #;
%put # additional content will be generated, #;
%put # name of the directory created is set to #;
%put # `<packagename>_AdditionalContent`, the default #;
%put # location is `%nrstr(%%sysfunc(pathname(WORK)))` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
%put # package is provided in required version, #;
%put # default value: `.` #;
%put # #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put ### Example 1 ###################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading additional content #;
%put # for the SQLinDS package. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%loadPackageAddCnt(SQLinDS) %%* load additional content for the package; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put # #;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofloadPackageAddCnt;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp zip;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let stimer_tmp = %sysfunc(getoption(stimer));
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
%let zip = zip;
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_;
call symputX("_PackageFileref_", "A" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
call symputX("_TargetFileref_", "T" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip."
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
filename &_PackageFileref_. &ZIP.
/* check existence of addcnt.zip inside package */
"&path./%lowcase(&packageName.).&zip."
member='addcnt.zip'
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
/* get metadata */
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip."
;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
/* test if required version of package is "good enough" */
%local rV pV;
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
+ (%scan(&pV.,2,.,M)+0)*1e4
+ (%scan(&pV.,3,.,M)+0)*1e0);
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
+ (%scan(&rV.,2,.,M)+0)*1e4
+ (%scan(&rV.,3,.,M)+0)*1e0);
%if %sysevalf(&rV. > &pV.) %then
%do;
%put ERROR: Additional content for package &packageName. will not be loaded!;
%put ERROR- Required version is &requiredVersion.;
%put ERROR- Provided version is &packageVersion.;
%put ERROR- Verify installed version of the package.;
%put ERROR- ;
%GOTO WrongVersionOFPackageAddCnt; /*%RETURN;*/
%end;
/*options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;*/
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip."
member='addcnt.zip'
;
/*********************/
filename &_TargetFileref_. "&target.";
%if %sysfunc(fexist(&_TargetFileref_.)) %then
%do;
%if %sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent)) %then
%do; /* dir for AC already exists */
%put WARNING: Target location:;
%put WARNING- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
%put WARNING- already exist. Please remove it manually to upload additional contents.;
%put WARNING- Additional Content will not be loaded.;
%put WARNING- ;
%end;
%else
%do;
/*-+-+-+-*/
/* create target location */
%put INFO:;
%put Additional content will be located in:;
%put %sysfunc(dcreate(%lowcase(&packageName.)_AdditionalContent,%sysfunc(pathname(&_TargetFileref_.))));
%if NOT (%sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent))) %then
%do; /* dir for AC cannot be generated */
%put ERROR: Cannot create target location:;
%put ERROR- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
%put ERROR- Additional Content will not be loaded.;
%put ERROR- ;
%end;
%else
%do;
/* extract addcnt.zip to work and, if successful, load additional content */
%put NOTE- **%sysfunc(DoSubL(%nrstr(
;
options nonotes nosource ps=min ls=max;
data _null_;
call symputx("AdditionalContent", 0, "L");
rc1=filename("in", pathname("&_PackageFileref_."), "ZIP", "lrecl=1 recfm=n member='addcnt.zip'");
rc1txt=sysmsg();
if fexist("in") then
do;
rc2=filename("out", pathname("WORK")!!"/%lowcase(&packageName.)addcnt.zip", "disk", "lrecl=1 recfm=n");
rc2txt=sysmsg();
rc3=fcopy("in","out");
rc3txt=sysmsg();
if rc3 then put _N_ @12 (rc:) (=);
if fexist("out") then
do;
call symputx("AdditionalContent", 1, "L");
end;
else put "INFO: No additional content for package &packageName..";
rc1=filename("in");
rc2=filename("out");
end;
else
do;
call symputx("AdditionalContent", 0, "L");
put "INFO: No additional content for package &packageName..";
end;
run;
%if &AdditionalContent. %then
%do;
filename f DUMMY;
filename f ZIP "%sysfunc(pathname(WORK))/%lowcase(&packageName.)addcnt.zip";
options dlCreateDir;
libname outData "%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent";
data WORK.__&_TargetFileref_._zip___;
did = dopen("f");
if not did then
do;
put "ERROR: Can not access Additional Content data.";
stop;
end;
if did then
do i=1 to dnum(did);
file = dread(did, i);
output;
keep file;
end;
did = dclose(did);
run;
data _null_;
set WORK.__&_TargetFileref_._zip___ end = EOF;
wc = countw(file,"/\");
libText = pathname("outData", "L");
if scan(file, wc , "/\") = "" then
do j = 1 to wc-1;
libText = catx("/", libText, scan(file, j , "/\"));
rc = libname("test", libText);
rc = libname("test");
end;
else
do;
do j = 1 to wc-1;
libText = catx("/", libText, scan(file, j , "/\"));
rc = libname("test", libText);
rc = libname("test");
end;
rc1 = filename("in", pathname("f"), "zip", "member='" !! strip(file) !! "' lrecl=1 recfm=n");
rc1msg = sysmsg();
rc2 = filename("out", catx("/", libText, scan(file, j , "/\")), "disk", "lrecl=1 recfm=n");
rc2msg = sysmsg();
rc3 = fcopy("in", "out");
rc3msg = sysmsg();
loadingProblem + (rc3 & 1);
if rc3 then
do;
put "ERROR: Cannot extract: " file;
put (rc1 rc2 rc3) (=);
put (rc1msg rc2msg rc3msg) (/);
put "ERROR-";
end;
crc1=filename("in");
crc2=filename("out");
end;
if EOF and loadingProblem then
do;
put "ERROR: Not all files from Additional Content were extracted successfully!";
end;
run;
data _null_;
rc = fdelete("f");
run;
proc delete data = WORK.__&_TargetFileref_._zip___;
run;
libname outData;
filename f DUMMY;
%end;
)))**;
%end;
/*-+-+-+-*/
%end;
%end;
%else
%do;
%put ERROR: Cannot access target location:;
%put ERROR- %sysfunc(pathname(&_TargetFileref_.));
%put ERROR- Additional Content will not be loaded.;
%put ERROR- ;
%end;
filename &_TargetFileref_. clear;
/*********************/
%end;
%else %put INFO: No additional content for &packageName. package.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
%WrongVersionOFPackageAddCnt:
/* restore optionos */
options ls = &ls_tmp. ps = &ps_tmp.
&notes_tmp. &source_tmp.
&stimer_tmp. &fullstimer_tmp.
msglevel=&msglevel_tmp.;
%ENDofloadPackageAddCnt:
%mend loadPackageAddCnt;
/**/

111
SPF/Macros/loadpackages.sas Normal file
View File

@@ -0,0 +1,111 @@
/*+loadPackageS+*/
/*** HELP START ***/
%macro loadPackageS(
packagesNames /* A comma separated list of packages names,
e.g. myPackage, myPackage1, myPackage2, myPackage3
required and not null.
Package version, in brackets behind a package name,
can be provided, e.g.
%loadPackageS(myPackage1(1.7), myPackage2(4.2))
*/
)/secure
/*** HELP END ***/
des = 'Macro to load multiple SAS packages at one run, version 20230207. Run %loadPackages() for help info.'
parmbuff
;
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `loadPackageS` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro wrapper for the loadPackage macro, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and embedded inside the zip. #;
%put # #;
%put # The `%nrstr(%%loadPackageS())` allows to load multiple packages at one time, #;
%put # *ONLY* from the *ZIP* with *DEFAULT OPTIONS*, into the SAS session. #;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packagesNames` A comma separated list of packages names, #;
%put # e.g. myPackage, myPackage1, myPackage2, myPackage3 #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%loadPackageS(myPackage1, myPackage2, myPackage3))`. #;
%put # Package version, in brackets behind a package name, can #;
%put # be provided, example is the following: #;
%put # `%nrstr(%%loadPackageS(myPackage1(1.7), myPackage2(4.2)))`. #;
%put # If empty displays this help information. #;
%put # #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ####################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS DFA) %%* install packages from the Internet; );
%put %nrstr( %%loadPackageS(SQLinDS, DFA) %%* load packags content into the SAS session; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofloadPackageS;
%end;
%local lengthOfsyspbuff numberOfPackagesNames i packageElement packageName packageVersion str;
%let lengthOfsyspbuff = %qsysfunc(length(&syspbuff.));
%let packagesNames = %qsysfunc(compress(%qsubstr(&syspbuff., 2, %eval(&lengthOfsyspbuff.-2)), {[(. _,)]}, KDA));
%let str = %qsysfunc(translate(%superq(packagesNames),[[ ]],{(,)}));
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
%let str = %qsysfunc(compbl(%superq(str)));
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
%let str = %qsysfunc(translate(%superq(str),(),[]));
%let packagesNames = %unquote(&str.);
%let numberOfPackagesNames = %qsysfunc(countw(&packagesNames., %str( )));
%put NOTE: List of packages to be loaded contains &numberOfPackagesNames. element(s).;
%put NOTE- The list is: &packagesNames..;
%put NOTE- ;
%do i = 1 %to &numberOfPackagesNames.;
%let packageElement = %qscan(&packagesNames., &i., %str( ) );
%let packageName = %qscan(&packageElement., 1, %str(()));
%let packageVersion = %qscan(&packageElement., 2, %str(()));
%if %superq(packageVersion) = %then %let packageVersion = .;
%loadPackage(%unquote(&packageName.), requiredVersion=%unquote(&packageVersion.))
%end;
%ENDofloadPackageS:
%mend loadPackageS;

View File

@@ -0,0 +1,159 @@
/*+previewPackage+*/
/*** HELP START ***/
%macro previewPackage(
packageName /* name of a package,
e.g. myPackageFile.zip,
required and not null */
, helpKeyword /* phrase to search for preview,
when empty prints description
"*" means prints all */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
, source2 = /*source2*/ /* option to print out details,
null by default */
, zip = zip /* standard package is zip (lowcase),
e.g. %previewPackage(PiPackage,*)
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use previewPackage in the form:
%previewPackage(PiPackage, *, zip=disk, options=)
*/
)/secure
/*** HELP END ***/
des = 'Macro to preview content of a SAS package, version 20230207. Run %previewPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `previewPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to get previwe of a SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and provided with #;
%put # a single `preview.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%previewPackage())` macro prints, in the SAS log, content #;
%put # of a SAS package. Code of a package is printed out. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%previewPackage(myPackage)).` #;
%put # If empty displays this help information. #;
%put # #;
%put # 2. `helpKeyword` *Optional.* A phrase to search in preview, #;
%put # - when empty prints description, #;
%put # - "*" means: print all preview. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
%put # default value: `LOWCASE_MEMNAME` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `zip=` Standard package is zip (lowcase), #;
%put # e.g. `%nrstr(%%previewPackage(PiPackage))`. #;
%put # If the zip is not available use a folder. #;
%put # Unpack data to "pipackage.disk" folder #;
%put # and use previewPackage in the following form: #;
%put # `%nrstr(%%previewPackage(PiPackage, , zip=disk, options=))` #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ####################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%previewPackage(SQLinDS) %%* get content of the package; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofpreviewPackage;
%end;
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
ENCODING =
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%include &_PackageFileref_.(preview.sas) / &source2.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp. msglevel = &msglevel_tmp.;
%ENDofpreviewPackage:
%mend previewPackage;

View File

@@ -0,0 +1,156 @@
/*+unloadPackage+*/
/*** HELP START ***/
%macro unloadPackage(
packageName /* name of a package,
e.g. myPackage,
required and not null */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
, source2 = /*source2*/ /* option to print out details,
null by default */
, zip = zip /* standard package is zip (lowcase),
e.g. %unloadPackage(PiPackage)
if the zip is not available use a folder
unpack data to "pipackage.disk" folder
and use unloadPackage in the form:
%unloadPackage(PiPackage, zip=disk, options=)
*/
)/secure
/*** HELP END ***/
des = 'Macro to unload SAS package, version 20230207. Run %unloadPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `unloadPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to unload SAS packages, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and provided with #;
%put # a single `unload.sas` file (also embedded inside the zip). #;
%put # #;
%put # The `%nrstr(%%unloadPackage())` macro clears the package content #;
%put # from the SAS session. #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%unloadPackage(myPackage)).` #;
%put # If empty displays this help information. #;
%put # #;
%put # - `path=` *Optional.* Location of a package. By default it #;
%put # looks for location of the **packages** fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
%put # default value: `LOWCASE_MEMNAME` #;
%put # #;
%put # - `source2=` *Optional.* Option to print out details about #;
%put # what is loaded, null by default. #;
%put # #;
%put # - `zip=` Standard package is zip (lowcase), #;
%put # e.g. `%nrstr(%%unloadPackage(PiPackage))`. #;
%put # If the zip is not available use a folder. #;
%put # Unpack data to "pipackage.disk" folder #;
%put # and use unloadPackage in the following form: #;
%put # `%nrstr(%%unloadPackage(PiPackage, zip=disk, options=))` #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put ### Example #####################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofunloadPackage;
%end;
/* local variables for options */
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_. &ZIP.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp.;
filename &_PackageFileref_. &ZIP.
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
ENCODING =
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
%else utf8 ;
;
%include &_PackageFileref_.(unload.sas) / &source2.;
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp. &notes_tmp. &source_tmp. msglevel = &msglevel_tmp.;
%ENDofunloadPackage:
%mend unloadPackage;

View File

@@ -0,0 +1,184 @@
/*+verifyPackage+*/
/*** HELP START ***/
%macro verifyPackage(
packageName /* name of a package,
e.g. myPackage,
required and not null */
, path = %sysfunc(pathname(packages)) /* location of a package,
by default it looks for
location of "packages" fileref */
, hash = /* The SHA256 hash digest for
the package generated by
hashing_file() function, SAS 9.4M6 */
)/secure
/*** HELP END ***/
des = 'Macro to verify SAS package with the hash digest, version 20230207. Run %verifyPackage() for help info.'
;
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
%do;
%local options_tmp ;
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
msglevel=%sysfunc(getoption(msglevel))
;
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
%put ;
%put #################################################################################;
%put ### This is short help information for the `verifyPackage` macro #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Macro to verify SAS package with it hash digest, version `20230207` #;
%put # #;
%put # A SAS package is a zip file containing a group #;
%put # of SAS codes (macros, functions, data steps generating #;
%put # data, etc.) wrapped up together and embedded inside the zip. #;
%put # #;
%put # The `%nrstr(%%verifyPackage())` macro generate package SHA256 hash #;
%put # and compares it with the one provided by the user. #;
%put # #;
%put # #;
%put # *Minimum SAS version required for the process is 9.4M6.* #;
%put # #;
%put #### Parameters: #;
%put # #;
%put # 1. `packageName` Name of a package, e.g. myPackage, #;
%put # Required and not null, default use case: #;
%put # `%nrstr(%%loadPackage(myPackage))`. #;
%put # If empty displays this help information. #;
%put # #;
%put # - `hash=` A value of the package `SHA256` hash. #;
%put # Provided by the user. #;
%put # #;
%put # - `path=` Location of a package. By default it looks for #;
%put # location of the "packages" fileref, i.e. #;
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
%put # #;
%put #-------------------------------------------------------------------------------#;
%put # #;
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
%put # to learn more. #;
%put # #;
%put #### Example ####################################################################;
%put # #;
%put # Enabling the SAS Package Framework #;
%put # from the local directory and installing & loading #;
%put # the SQLinDS package from the Internet. #;
%put # #;
%put # Assume that the `SPFinit.sas` file #;
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
%put # #;
%put # Run the following code in your SAS session: #;
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* set-up a directory for packages; );
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
%put ;
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
%put %nrstr( %%verifyPackage%(SQLinDS, %%* verify the package with provided hash; );
%put %nrstr( hash=HDA478ANJ3HKHRY327FGE88HF89VH89HFFFV73GCV98RF390VB4%) );
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
%put #################################################################################;
%put ;
options &options_tmp.;
%GOTO ENDofverifyPackage;
%end;
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
%let ls_tmp = %sysfunc(getoption(ls));
%let ps_tmp = %sysfunc(getoption(ps));
%let notes_tmp = %sysfunc(getoption(notes));
%let source_tmp = %sysfunc(getoption(source));
%let stimer_tmp = %sysfunc(getoption(stimer));
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
%let msglevel_tmp = %sysfunc(getoption(msglevel));
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
%local _PackageFileref_;
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
/* when the packages reference is multi-directory search for the first one containing the package */
data _null_;
exists = 0;
length packages $ 32767 p $ 4096;
packages = resolve(symget("path"));
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
do i = 1 to kcountw(packages, "()", "QS");
p = dequote(kscanx(packages, i, "()", "QS"));
exists + fileexist(catx("/", p, "%lowcase(&packageName.).zip"));
if exists then leave;
end;
if exists then call symputx("path", p, "L");
run;
filename &_PackageFileref_.
/* put location of package myPackageFile.zip here */
"&path./%lowcase(&packageName.).zip"
;
%if %sysfunc(fexist(&_PackageFileref_.)) %then
%do;
/* create hash SHA256 id *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
%local HASHING_FILE_exist;
%let HASHING_FILE_exist = 0;
%if %sysfunc(exist(sashelp.vfunc, VIEW)) %then
%do;
data _null_;
set sashelp.vfunc(keep=fncname);
where fncname = "HASHING_FILE";
call symputX('HASHING_FILE_exist', 1, "L");
stop;
run;
%end;
%if &HASHING_FILE_exist. = 1 %then
%do;
options notes;
filename &_PackageFileref_. list;
data _null_;
length providedHash $ 100;
providedHash = strip(symget("hash"));
select;
when ( 'F*' = upcase(substr(providedHash,1,2)) ) /* F = file digest */
SHA256 = 'F*' !! HASHING_FILE("SHA256", pathname("&_PackageFileref_.",'F'), 0);
when ( 'C*' = upcase(substr(providedHash,1,2)) ) /* C = content digest */
SHA256 = 'C*' !! HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
otherwise /* legacy approach, without C or F, digest value equivalent to C */
SHA256 = HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
end;
put "Provided Hash: " providedHash;
put "SHA256 digest: " SHA256;
put " ";
if upcase(SHA256) = upcase(providedHash) then
do;
put "NOTE: Package verification SUCCESSFUL.";
put "NOTE- Generated hash is EQUAL to the provided one.";
end;
else
do;
put "ERROR: Package verification FAILED!!";
put "ERROR- Generated hash is DIFFERENT than the provided one.";
put "ERROR- Confirm if the package is genuine.";
end;
run;
%let HASHING_FILE_exist = 0;
%end;
%else
%put WARNING: Verification impossible! Minimum SAS version required for the process is 9.4M6. ;
/*-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
%end;
%else %put ERROR:[&sysmacroname] File "&path./&packageName..zip" does not exist!;
filename &_PackageFileref_. clear;
options ls = &ls_tmp. ps = &ps_tmp.
&notes_tmp. &source_tmp.
&stimer_tmp. &fullstimer_tmp.
msglevel=&msglevel_tmp.;
%ENDofverifyPackage:
%mend verifyPackage;
/**/

View File

@@ -10,25 +10,26 @@
* [the `previewPackage` macro](#previewPackage)
* [the `generatePackage` macro](#generatepackage)
* [the `extendPackagesFileref` macro](#extendpackagesfileref)
* [the `loadPackageAddCnt` macro](#loadpackageaddcnt)
* [Some more examples](#some-more-examples)
---
## This is short SAS PAckages Framework help information <a name="helpinfo"></a>
## This is short SAS Packages Framework help information <a name="helpinfo"></a>
A **SAS package** is an automatically generated, single, stand alone *zip* file containing organised and ordered code structures, created by the developer and extended with additional automatically generated "driving" files (i.e. description, metadata, load, unload, and help files).
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20220420`**.
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20230207`**.
**To get started with SAS Packages** try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
**The documentation and more advance reading** would be the [**`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article (see the `./SPF/Documentation` directory).
*Note:* Filenames references `packages` and `package` are reserved keywords.
*Note:* Filenames references `packages` and `package` are **reserved keywords.**
The first one should be used to point local folder with packages and the framework.
The second is used internally by macros.
After assigning the directory do not change them when using the SPF since it may affect stability of the framework.
@@ -39,7 +40,7 @@ After assigning the directory do not change them when using the SPF since it may
## This is short help information for the `installPackage` macro <a name="installpackage"></a>
--------------------------------------------------------------------------------------------
Macro to install SAS packages, version `20220420`
Macro to install SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -65,13 +66,28 @@ After assigning the directory do not change them when using the SPF since it may
then the framework itself is downloaded.
- `sourcePath=` Location of the package, e.g. "www.some.web.page/" (mind the "/" at the end of the path!)
Current default location for packages is:
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/`
Current default location for the framework is:
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/`
Current default location for packages is:
`https://github.com/SASPAC/`
Current default location for the framework is:
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/`
- `mirror=` Indicates which web location for packages installation is used.
Value `0` indicates:
`https://github.com/SASPAC/`
Value `1` indicates:
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main`
Value `2` indicates:
`https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES`
Default value is `0`.
- `version=` Indicates which historical version of a package to install.
Historical version are available only if `mirror=0` is set.
Default value is null which means "install the latest".
When there are multiple packages to install version
is scan sequentially.
- `replace=` With default value of `1` it causes existing package file
to be replaceed by new downloaded file.
to be replaced by new downloaded file.
- `URLuser=` A user name for the password protected URLs, no quotes needed.
@@ -79,6 +95,13 @@ After assigning the directory do not change them when using the SPF since it may
- `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS
documentation for the further details.
- `loadAddCnt=` *Optional.* A package zip may contain additional
content. The option indicates if it should be loaded
Default value of zero (`0`) means "No", one (`1`)
means "Yes". Content is extracted into the **packages** fileref
directory in `<packageName>_AdditionalContent` folder.
For other locations use `%loadPackageAddCnt()` macro.
--------------------------------------------------------------------------------------------
@@ -104,11 +127,29 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Example ################################################################################
Enabling the SAS Package Framework
from the local directory and installing & loading
the multiple packages from the Internet.
Assume that the `SPFinit.sas` file
is located in the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
filename packages "C:/SAS_PACKAGES";
%include packages(SPFinit.sas);
%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM)
%loadPackageS(GSM, baseplus(1.17), macroarray(1.0), dfa(0.5))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## This is short help information for the `helpPackage` macro <a name="helppackage"></a>
-------------------------------------------------------------------------------
Macro to get help about SAS packages, version `20220420`
Macro to get help about SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -174,11 +215,12 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---
## This is short help information for the `loadPackage` macro <a name="loadpackage"></a>
-------------------------------------------------------------------------------
Macro to *load* SAS packages, version `20220420`
Macro to *load* SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -210,24 +252,36 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
package is provided in required version,
default value: `.`
- `lazyData=` *Optional.* A list of names of lazy datasets to be
loaded. If not null datasets from the list are loaded
instead of the package.
- `lazyData=` *Optional.* A space separated list of names of lazy
datasets to be loaded. If not null datasets from the
list are loaded instead of the package.
An asterisk (*) means *load all lazy datasets*.
- `zip=` Standard package is zip (lowcase),
- `zip=` *Optional.* Standard package is zip (lowcase),
e.g. `%loadPackage(PiPackage)`.
If the zip is not available use a folder.
Unpack data to "pipackage.disk" folder
and use loadPackage in the following form:
`%loadPackage(PiPackage, zip=disk, options=)`
- `cherryPick=` *Optional.* A space separated list of selected elements
of the package to be loaded into the SAS session.
Default value of an asterisk (*) means:
"load all elements of the package".
- `loadAddCnt=` *Optional.* A package zip may contain additional
content. The option indicates if it should be loaded
Default value of zero (`0`) means "No", one (`1`)
means "Yes". Content is extracted into the **Work**
directory in `<packageName>_AdditionalContent` folder.
For other locations use `%loadPackageAddCnt()` macro.
-------------------------------------------------------------------------------
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
to learn more.
## Example ####################################################################
## Example 1 ##################################################################
Enabling the SAS Package Framework
from the local directory and installing & loading
@@ -247,11 +301,74 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Example 2 ##################################################################
Enabling the SAS Package Framework
from the local directory and installing & cherry picking
elements of the BasePlus package.
Assume that the `SPFinit.sas` file
is located in the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%installPackage(BasePlus) %* install the package from the Internet;
%loadPackage(BasePlus, cherryPick=getVars) %* cherry pick the content;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Utility macros generated during loading a package ###########################
If a package contains IML modules or CASL user defined functions additional
utility macros for IML Modules and CASL UDFs are generated when package is loaded.
Macros are generated with the following names: `%<packageName>IML()` and `%<packageName>CASLudf()`.
Their purpose is to make loading of Modules or UDFs (with potentially multiple
dependencies) easy in Proc IML and Proc CAS.
Run them, accordingly, as the first line in the Proc IML or Proc CAS to access the package content.
For Proc IML the use is as follows:
~~~~~~sas
proc IML;
%<packageName>IML()
<... your code using IML modules from the package ...>
quit;
~~~~~~
For Proc CAS the use is as follows:
~~~~~~sas
proc CAS;
%<packageName>CASLudf()
<... your code using CASL UDFs from the package ...>
quit;
~~~~~~
If a utility macro is generated appropriate note and a code snippet
is printed in the log of the package loading process.
In 99% cases macros are used with default parameters values but,
in case when deeper insight about macros parameters is needed,
help info is printed in the log when the following code is run:
~~~~~~sas
%<packageName>IML(list=HELP)
~~~~~~
or
~~~~~~sas
%<packageName>CASLudf(list=HELP)
~~~~~~
If created, those macros are automatically deleted when the `%unloadPackage()` macro is run.
---
## This is short help information for the `loadPackageS` macro <a name="loadpackages"></a>
-------------------------------------------------------------------------------
Macro wrapper for the loadPackage macro, version `20220420`
Macro wrapper for the loadPackage macro, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -300,7 +417,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `unloadPackage` macro <a name="unloadpackage"></a>
-------------------------------------------------------------------------------
Macro to unload SAS packages, version `20220420`
Macro to unload SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -365,7 +482,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `listPackages` macro <a name="listpackages"></a>
-----------------------------------------------------------------------------------------
Macro to list available SAS packages, version `20220420`
Macro to list available SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -406,7 +523,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `verifyPackage` macro <a name="verifypackage"></a>
-------------------------------------------------------------------------------
Macro to verify SAS package with it hash digest, version `20220420`
Macro to verify SAS package with it hash digest, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -460,7 +577,7 @@ filename packages "C:/SAS_PACKAGES"; %* set-up a directory for packages;
## This is short help information for the `previewPackage` macro <a name="previewpackage"></a>
-------------------------------------------------------------------------------
Macro to get previwe of a SAS packages, version `20220420`
Macro to get previwe of a SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -527,7 +644,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
## This is short help information for the `generatePackage` macro <a name="generatepackage"></a>
-------------------------------------------------------------------------------
Macro to generate SAS packages, version `20220420`
Macro to generate SAS packages, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -567,10 +684,15 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
- `sasexe=` Location of a DIRECTORY where the SAS binary is located,
if null (the default) then the `!SASROOT` is used.
- `sascfgfile=` Location of a FILE with testing session configuration
- `sascfgFile=` Location of a FILE with testing session configuration
parameters, if null (the default) then no config file
is pointed during the SAS invocation,
if set to `DEF` then the `!SASROOT/sasv9.cfg` is used.
- `delTestWork=` Indicates if `WORK` directories generated by user tests
should be deleted, i.e. the (NO)WORKTERM option is set.
The default value: `1` means "delete tests work".
Available values are `0` and `1`.
-------------------------------------------------------------------------------
@@ -588,7 +710,7 @@ The file should contain the following obligatory information:
Type: Package
Package: PackageName
Title: A title/brief info for log note about your package.
Version: X.Y
Version: X.Y.Z
Author: Firstname1 Lastname1 (xxxxxx1@yyyyy.com), Firstname2 Lastname2 (xxxxxx2@yyyyy.com)
Maintainer: Firstname Lastname (xxxxxx@yyyyy.com)
License: MIT
@@ -612,6 +734,9 @@ Name of the `type` of folder and `files.sas` inside must be in the _low_ case le
If order of loading is important, the sequential number
can be used to order multiple types in the way you wish.
If folder name starts with `!` (e.g., `!ignore_me`) or *type* of the folder is "unknown" (e.g., not supported one)
the content of such folder is ignored during package generation process.
The "tree structure" of the folder could be for example as follows:
All files have to have `.sas` extension. Other files are ignored.
@@ -689,6 +814,15 @@ All files have to have `.sas` extension. Other files are ignored.
|
+-...
|
+-998_addcnt [additional content for the package, can be only one!, content of this
| | directory is copied "as is"]
| |
| +-arbitrary_file1 [an arbitrary file ]
| |
| +-subdirectory_with_files [an arbitrary directory with some files inside]
| |
| +-...
|
+-999_test [tests executed during package generation, XCMD options must be turned-on]
| |
| +-test1.sas [a file with a code for test1]
@@ -703,7 +837,7 @@ All files have to have `.sas` extension. Other files are ignored.
## This is short help information for the `extendPackagesFileref` macro <a name="extendpackagesfileref"></a>
-----------------------------------------------------------------------------------------
Macro to list directories pointed by 'packages' fileref, version `20220420`
Macro to list directories pointed by 'packages' fileref, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
@@ -738,9 +872,98 @@ filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %* setup a directory for packages
filename packages ("D:/NEW_DIR" %extendPackagesFileref()); %* add new directory;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-----------------------------------------------------------------------------------------
## This is short help information for the `loadPackageAddCnt` macro <a name="loadpackageaddcnt"></a>
-------------------------------------------------------------------------------
Macro to load *additional content* for a SAS package, version `20230207`
A SAS package is a zip file containing a group
of SAS codes (macros, functions, data steps generating
data, etc.) wrapped up together and included by
a single `load.sas` file (also embedded inside the zip).
The `%loadPackageAddCnt()` macro loads additional content
for a package (of course only if one is provided).
-------------------------------------------------------------------------------
### Parameters:
1. `packageName` *Required.* Name of a package, e.g. myPackage,
Required and not null, default use case:
`%loadPackageAddCnt(myPackage)`.
If empty displays this help information.
- `path=` *Optional.* Location of a package. By default it
looks for location of the **packages** fileref, i.e.
`%sysfunc(pathname(packages))`
- `target=` *Optional.* Location where the directory with
additional content will be generated,
name of the directory created is set to
`<packagename>_AdditionalContent`, the default
location is `%sysfunc(pathname(WORK))`
- `source2=` *Optional.* Option to print out details about
what is loaded, null by default.
- `requiredVersion=` *Optional.* Option to test if the loaded
package is provided in required version,
default value: `.`
-------------------------------------------------------------------------------
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
to learn more.
-------------------------------------------------------------------------------
By *default* additional content is not deployed automatically e.g.,
from security point of view, or production job doesn't need it to run, etc.
But if there is a need for it there are three ways to get it:
- The first one ("by-the-book"), and also the recommended one. The additional
content is extracted during the automatic installation process using the
`\%installPackage()` macro. For this to work the `loadAddCnt=` parameter
has to be set to `1`. The additional content is extracted to the
`<packageName>_AdditionalContent` directory into the same location where
the package is installed i.e., inside `packages` fileref location.
- The second one ("by-the-work"), when the additional content is extracted
during the loading process with the `\%loadPackage()` macro. For this to
work also the `loadAddCnt=` parameter has to be set to `1`. The additional
content is extracted to the `<packageName>_AdditionalContent` directory
inside the `Work` library location.
- The third one ("by-the-user"), when the additional content is extracted
with dedicated `%loadPackageAddCnt()` macro. By default the additional
content is extracted to the `<packageName>_AdditionalContent` directory
inside the `Work` library location too, but it can be altered by changing
the `target=` parameter, which indicates the location.
If done "by-the-book", or "by-the-user" with `target=` parameter, the
additional content is not automatically deleted when SAS session ends,
in this case the "additionals" have to be deleted manually by the User.
### Example 1 ##################################################################
Enabling the SAS Package Framework
from the local directory and installing & loading additional content
for the SQLinDS package.
Assume that the `SPFinit.sas` file
is located in the "C:/SAS_PACKAGES/" folder.
Run the following code in your SAS session:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
%include packages(SPFinit.sas); %* enable the framework;
%installPackage(SQLinDS) %* install the package from the Internet;
%loadPackageAddCnt(SQLinDS) %* load additional content for the package;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-------------------------------------------------------------------------------
## Some more examples <a name="some-more-examples"></a> #############################################################

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
Copyright (c) 2019 - 2022 Bartosz Jablonski
Copyright (c) 2019 - 2023 Bartosz Jablonski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,11 +2,15 @@
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
## Available packages:
Currently the following packages are available:
For "backward compatibility"/historical point of view the following packages are available under the `./packages` directory.
Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
Packages:
---
- **SQLinDS**\[2.2\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
- **SQLinDS**\[2.2.4\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
```sas
data class;
set %SQL(
@@ -18,21 +22,13 @@ data class;
WH = weight + height;
run;
```
SHA256 digest for SQLinDS: 701B69BE71B99792803BCE7718ED486259310FFB92E6D77ED1BC029D9CC67B60
SHA256 digest for SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
---
- **MacroCore**\[1\], a macro library for SAS application developers. Over 100 macros for Base SAS, metadata, and Viya. Provided by the [SASjs framework](https://sasjs.io "SASjs framework").
SHA256 digest for MacroCore: A23C29529F3CE7D0C8BEE9545C5D22D5B5594907547374A5135B8E5A48D7687B
[Documentation for MacroCore](https://core.sasjs.io "Documentation for MacroCore")
---
- **DFA** (Dynamic Function Arrays)\[0.5\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
- **DFA** (Dynamic Function Arrays)\[0.5.4\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
```sas
%createDFArray(ArrDynamic, resizefactor=17);
@@ -59,13 +55,13 @@ data _null_;
end;
run;
```
SHA256 digest for DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388BBA704EA
SHA256 digest for DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
---
- **macroArray**\[1.0\], implementation of an array concept in a macro language, e.g.
- **macroArray**\[1.0.4\], implementation of an array concept in a macro language, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -84,13 +80,13 @@ SHA256 digest for DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388B
which = 1:H:2
);
```
SHA256 digest for macroArray: DF63B0E027827A82038F1C8422787A0BC569BA93104BA1778DB6DD088A5D255C
SHA256 digest for macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
---
- **BasePlus**\[1.17\] adds a bunch of functionalities I am missing in BASE SAS, such as:
- **BasePlus**\[1.18.4\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```sas
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
@@ -108,25 +104,25 @@ format x bool.;
%zipLibrary(sashelp,libOut=work)
```
SHA256 digest for BasePlus: 619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD
SHA256 digest for BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
---
- **GSM** (Generate Secure Macros)\[0.20\], package allows
- **GSM** (Generate Secure Macros)\[0.20.4\], package allows
to create secured macros stored in SAS Proc FCMP functions.
The dataset with functions can be shared between different operating systems
and allows to generate macros on site without showing their code.
SHA256 digest for GSM: E6E2A6214EE7DC6E06AA76916A68B216DD7665184E63CF2C01F487A038E71B09
SHA256 digest for GSM: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
---
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
- **dynMacroArray**\[0.2.4\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
SHA256 digest for dynMacroArray: 7DA9BFDED37C18C4FB5BD7579A81A4B2578EEEF1546D1A3AB5C80DE07C88A615
SHA256 digest for dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
---

View File

@@ -1,3 +1,45 @@
/* 20221215 */
BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
GSM: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
/* 20221125 */
BasePlus: D8DBB7CC5952331FA59FEBBBDD15BC543FE3C89A8BA9150FE6AF5E412868EBE7
DFA: 7520CF21CBF1FD4AD2BC05C5DD343E508FCEA507575EBC060B4AD322FB80AB04
dynMacroArray: 440920272D1838505EA5C033B1C448C612DE2FCCFD57F157BB90ED980E4001CC
GSM: 50D8340E080BEA459E68BE315146AD3B809930DB8DC7B23C7A492C3815ACD83F
macroArray: 244B88C82AD7E6E93B8B85BC701ECDDB20B68F38B16C500EE9B49E1167ADC298
SQLinDS: D5A66E60602270E5FB1E592FA3E0C2F2C640BC077FE799A2223CB9BA275F6F47
/* 20221121 */
BasePlus: EBA9EDB3D50D854288970CC0E965DA6AD5B057F6E6433EEBEC4A02B9A25CF6E2
DFA: 3F618EDAC8B4F4BE6C19D606E6BCC58121A16BA1383D2EE64C680B4B7FA9C96A
dynMacroArray: DD0BF1768DA05EBB5F8C6E7409A0929E28DF11CB499F75B433D9648855AACAE4
GSM: E47C94B536B661DEE390F5C3EA1684DD1A246106F4FBBDAFA57F5E34D4BB16D5
macroArray: DA57FFE85F49201FD61A53411D19E97FB5A6AC3C34E34FDF4B913545699551FF
SQLinDS: 085F0B8BD4A59343E2913FF9635EA6E551ADD54E9678C35F5096D4A0A895B9C5
/* 20221112 */
BasePlus: A80006D3C1409465E49F383D08F2F3AF1E33D6A67D71A8CAF29747ADC917E2E4
DFA: 5A6FD2F6E962E6C191346A141FFAF354E35A546CA93146B55D7C6163BFB1BDD6
dynMacroArray: C987C08615A53D7BD7AEC3911EADF436C676EAB3E233E7E422E42995B890E169
GSM: 5D1925970C9590CD195C15B8641B01D7857E3B2546323DC77D09154BCCA40922
macroArray: 371B92A5ABBE82C53F7D63BC5C0D1EBD4695603D3894D8A9A5D5777D1AB59B30
SQLinDS: A070214517CC36590083FCF9D5F488AC6E746793E94B9AA55D09A419CF291B5B
/* 20220830 */
BasePlus: 56B260350FEB7D5118F581B9EFD1B9CE1F0298DCB9A4C000A7654E2FF3F0298C
DFA: 5BFFCE78439E1CDDCBB15C95CD287AA4195BF64BB17DDB8FE374EC3535B4F491
dynMacroArray: D7E0B8F85C05EBF8622204E0D2F3E990D48D0A9B3911051C3AD44DC98954DDCF
GSM: 2AEBC150FBA99A4AAB0265A21C57E89200BFD96B633B898F32743D1C8831A159
macroArray: ED12BC96F8A4E9E7C4D651EC1E15479DB9B55D98B274B63C507ED842081F7AB7
SQLinDS: 96D0EFE02DF1AE0D7D875A10CAF7EF63CDEF85DD0CF9418934BEFAF0C067D453
/* 20220511 */
BasePlus: 619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD

View File

@@ -49,14 +49,14 @@
* [`%LDsNm()` macro](#ldsnm-macro)
* [`%LVarNm()` macro](#lvarnm-macro)
* [`%LVarNmLab()` macro](#lvarnmlab-macro)
* [`%bpPIPE()` macro](#bppipe-macro)
* [License](#license)
---
# The BasePlus package [ver. 1.17] <a name="baseplus-package"></a> ###############################################
# The BasePlus package [ver. 1.18.4] <a name="baseplus-package"></a> ###############################################
The **BasePlus** package implements useful
functions and functionalities I miss in the BASE SAS.
@@ -77,6 +77,8 @@ Kudos to all who inspired me to generate this package:
*Michal Ludwicki*,
*Quentin McMullen*.
Recording from the SAS Explore 2022 conference: [A BasePlus Package for SAS](https://communities.sas.com/t5/SAS-Explore-Presentations/A-BasePlus-Package-for-SAS/ta-p/838246 "A BasePlus Package for SAS") (September 27th-29th, 2022).
---
### BASIC EXAMPLES AND USECASES: ####################################################
@@ -218,63 +220,69 @@ data MyNextDataset;
run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Example 12**: List, to the log, content of `home` directory.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%bpPIPE(ls -la ~/)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---
Package contains:
1. macro deduplistc
2. macro deduplistp
3. macro deduplists
4. macro deduplistx
5. macro functionexists
6. macro getvars
7. macro ldsn
8. macro ldsnm
9. macro lvarnm
10. macro lvarnmlab
11. macro qdeduplistx
12. macro qgetvars
13. macro qzipevalf
14. macro raincloudplot
15. macro symdelglobal
16. macro unziplibrary
17. macro zipevalf
18. macro ziplibrary
19. format bool
20. format boolz
21. format ceil
22. format floor
23. format int
24. functions arrfill
25. functions arrfillc
26. functions arrmissfill
27. functions arrmissfillc
28. functions arrmisstoleft
29. functions arrmisstoleftc
30. functions arrmisstoright
31. functions arrmisstorightc
32. functions bracketsc
33. functions bracketsn
34. functions catxfc
35. functions catxfi
36. functions catxfj
37. functions catxfn
38. functions deldataset
39. functions semicolonc
40. functions semicolonn
41. format brackets
42. format semicolon
43. proto qsortincbyprocproto
44. functions frommissingtonumberbs
45. functions fromnumbertomissing
46. functions quicksort4notmiss
47. functions quicksorthash
48. functions quicksorthashsddv
49. functions quicksortlight
1. macro bppipe
2. macro deduplistc
3. macro deduplistp
4. macro deduplists
5. macro deduplistx
6. macro functionexists
7. macro getvars
8. macro ldsn
9. macro ldsnm
10. macro lvarnm
11. macro lvarnmlab
12. macro qdeduplistx
13. macro qgetvars
14. macro qzipevalf
15. macro raincloudplot
16. macro symdelglobal
17. macro unziplibrary
18. macro zipevalf
19. macro ziplibrary
20. format bool
21. format boolz
22. format ceil
23. format floor
24. format int
25. functions arrfill
26. functions arrfillc
27. functions arrmissfill
28. functions arrmissfillc
29. functions arrmisstoleft
30. functions arrmisstoleftc
31. functions arrmisstoright
32. functions arrmisstorightc
33. functions bracketsc
34. functions bracketsn
35. functions catxfc
36. functions catxfi
37. functions catxfj
38. functions catxfn
39. functions deldataset
40. functions semicolonc
41. functions semicolonn
42. format brackets
43. format semicolon
44. proto qsortincbyprocproto
45. functions frommissingtonumberbs
46. functions fromnumbertomissing
47. functions quicksort4notmiss
48. functions quicksorthash
49. functions quicksorthashsddv
50. functions quicksortlight
*SAS package generated by generatePackage, version 20220420*
*SAS package generated by generatePackage, version 20221215*
The SHA256 hash digest for package BasePlus:
`619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD`
`A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB`
---
# Content description ############################################################################################
@@ -3652,10 +3660,10 @@ The main idea behind the `%LDSNM()` is the same as for `%LDSN()` - see the descr
---
The `%LDSNM()` works differently then the `%LDSN()`.
The `%LDSNM()` macro works differently than the `%LDSN()` macro.
The `%LDSN()` assumed that *both* libname and dataset options *could*
be passed as elements in macro argument, e.g.
The `%LDSN()` macro assumes that *both* libname and dataset options *are*
be passed as elements **inside** the macro argument, together with the data set name. E.g.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
data %LDSN( WORK.peanut butter & jelly with a hot-dog in [a box] and s*t*a*r*s (drop = sex) );
@@ -3663,8 +3671,8 @@ data %LDSN( WORK.peanut butter & jelly with a hot-dog in [a box] and s*t*a*r*s (
run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The `%LDSNM()`, in contrary, assumes that both libname and dataset options are
passed **outside** the macro, i.e.
The `%LDSNM()` macro, in contrary, assumes that both libname and dataset options are
passed **outside** the macro parameter, i.e.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
data WORK.%LDSNM( peanut butter & jelly with a hot-dog in [a box] and s*t*a*r*s ) (drop = sex);
@@ -3672,12 +3680,13 @@ data WORK.%LDSNM( peanut butter & jelly with a hot-dog in [a box] and s*t*a*r*s
run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This approach reduces some limitations the LDSN has.
This approach overcomes some limitations the LDSN has.
The **additional** feature of the `%LDSNM()` is that when the macro is called
a global macrovariable, which name is the same as hashed dataset name, is created.
The macrovariable value is the text of the argument of the macro. For example
the following macro call:
The **additional** feature of the `%LDSNM()` is that when the macro is called,
a global macrovariable is created.
The macro variable name is the text of the hashed data set name.
The macro variable value is the text of the unhashed data set name (i.e. the argument of the macro).
For example the following macro call:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
data %LDSNM(John "x" 'y' dog);
@@ -3686,7 +3695,7 @@ data %LDSNM(John "x" 'y' dog);
run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
creates `DSN_BF1F8C4D6495B34A_` macrovariable with value: `JOHN "X" 'Y' DOG`.
creates macro variable with name `DSN_BF1F8C4D6495B34A_` and with value: `JOHN "X" 'Y' DOG`.
The macrovariable is useful when combined with `symget()` function and
the `indsname=` option to get the original text string value back,
@@ -3737,8 +3746,8 @@ The basic syntax is the following, the `<...>` means optional parameters:
)
~~~~~~~~~~~~~~~~~~~~~~~
The text string is concider as *"only dataset name"*, i.e. macro does not
assume it contain library as prefix or data set options as sufix.
The text string is considered as *"only dataset name"*, i.e. the macro does not
assume it contains library as prefix or data set options as suffix.
See the `%LDSN()` macro for comparison.
---
@@ -3802,7 +3811,7 @@ run;
The LVarNm() macro function works like the LDSN() macro function, but for variables.
Supported by LVarNmLab() macro function which allows to remember "user names" in labels.
The motivation for the macro was similar one as for the LDSN() macro.
The motivation for the macro was similar to that for the LDSN() macro.
---
@@ -3835,7 +3844,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
---
### EXAMPLES AND USECASES: ####################################################
### EXAMPLES AND USE CASES: ####################################################
**EXAMPLE 1.**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
@@ -3931,9 +3940,45 @@ The basic syntax is the following, the `<...>` means optional parameters:
---
## >>> `%bpPIPE()` macro: <<< <a name="bppipe-macro"></a> #######################
The bpPIPE() [Base Plus PIPE] macro executes OS command
and print to the log output of the execution.
Under the hood it uses `_` filename reference to PIPE device.
### SYNTAX: ###################################################################
The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%bpPIPE( <OS command goes here> )
~~~~~~~~~~~~~~~~~~~~~~~
**Arguments description**:
* **NO Arguments** - Everything inside brackets is treated as an OS command.
---
### EXAMPLES AND USECASES: ####################################################
**EXAMPLE 1.** List, to the log, content of D and C drives:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%bpPIPE(D: & dir & dir "C:\")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**EXAMPLE 2.** List, to the log, content of `home` directory:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%bpPIPE(ls -halt ~/)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---
## License ####################################################################
Copyright (c) 2020 Bartosz Jablonski
Copyright (c) since 2020 Bartosz Jablonski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

Binary file not shown.

View File

@@ -18,7 +18,7 @@
---
# The DFA package [ver. 0.5] <a name="dfa-package"></a> ###############################################
# The DFA package [ver. 0.5.4] <a name="dfa-package"></a> ###############################################
The **DFA** (a.k.a. *Dynamic Function Array*) package implements:
- dynamic numeric and character arrays,
@@ -52,10 +52,10 @@ Package contains:
12. exec generatearrays
13. clean generatearrays
*SAS package generated by generatePackage, version 20220420*
*SAS package generated by generatePackage, version 20221215*
The SHA256 hash digest for package BasePlus:
`6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388BBA704EA`
`6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034`
---
# Content description ############################################################################################

Binary file not shown.

Binary file not shown.

View File

@@ -8,7 +8,7 @@
---
# The GSM package [ver. 0.20] <a name="gsm-package"></a> ###############################################
# The GSM package [ver. 0.20.4] <a name="gsm-package"></a> ###############################################
The **GSM** (a.k.a. *Generate Secure Macros*) package allows
to create secured macros stored in SAS Proc FCMP functions.
@@ -91,10 +91,10 @@ Package contains:
Required SAS Components:
`Base SAS Software`
* SAS package generated by generatePackage, version 20220420 *
*SAS package generated by generatePackage, version 20221215*
The SHA256 hash digest for package GSM:
`E6E2A6214EE7DC6E06AA76916A68B216DD7665184E63CF2C01F487A038E71B09`
`83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524`
## >>> `%GSM()` macro: <<< <a name="gsm-macro"></a> #######################

Binary file not shown.

View File

@@ -19,7 +19,7 @@
---
# The macroArray package [ver. 1.0] <a name="macroarray-package"></a> ###############################################
# The macroArray package [ver. 1.0.4] <a name="macroarray-package"></a> ###############################################
The **macroArray** package implements a macro array facility:
- `%array()`,
@@ -75,10 +75,10 @@ Package contains:
Required SAS Components:
*Base SAS Software*
*SAS package generated by generatePackage, version 20220420.*
*SAS package generated by generatePackage, version 20221215*
The SHA256 hash digest for package macroArray:
`DF63B0E027827A82038F1C8422787A0BC569BA93104BA1778DB6DD088A5D255C`
`8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470`
---
# Content description ############################################################################################

Binary file not shown.

View File

@@ -1,4 +1,4 @@
- [The SQLinDS package [ver. 2.2]](#sqlinds-package)
- [The SQLinDS package](#sqlinds-package)
- [Content description](#content-description)
* [library `dsSQL`](#library-dssql)
* [`%dsSQL_inner()` macro](#dssql-inner-macro)
@@ -8,7 +8,7 @@
---
# The SQLinDS package [ver. 2.2] <a name="sqlinds-package"></a> ###############################################
# The SQLinDS package [ver. 2.2.4] <a name="sqlinds-package"></a> ###############################################
The **SQLinDS** package is an implementation of
the *macro-function-sandwich* concept introduced in the
@@ -46,10 +46,10 @@ Package contains:
Required SAS Components:
*Base SAS Software*
*SAS package generated by generatePackage, version 20220420*
*SAS package generated by generatePackage, version 20221215*
The SHA256 hash digest for package SQLinDS:
`701B69BE71B99792803BCE7718ED486259310FFB92E6D77ED1BC029D9CC67B60`
`42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0`
---
# Content description ############################################################################################

Binary file not shown.