Hi SAS-C!
Just FYI.
Bart
20251231Available as usual in: https://github.com/yabwon/SAS_PACKAGES
This release introduce concept of SAS packages bundles and two new macros to work with bundles. See detailed use case below to learn more about bundles.
A) Two new macros were added:
%bundlePackages() macro that allows to combine multiple SAS packages into SAS bundle,%unbundlePackages() macro that allows to extract SAS packages from a SAS bundle.B) Bug fix in the %verifyPackage() macro.
C) Minor updates in: %generatePackage(), %listPackages(), and %relocatePackage() macros.
D) Documentation updated.
In a single user environment, like local PC SAS or environments where users have their own separate space (e.g., SAS Workbench), keeping packages directories tidy and well organized may not necessary be a "highly required" demand, but in a setup where multiple users, or project teams, share centralized location for packages, the environment (e.g., packages versions) cannot be changed "just like that". Keeping the environment tidy can save programmers form so called "packages inferno", a situation where no one knows which version is where, which one is used, and "why my project is no longer working after packages update?".
On multiple occasions I've been highlighting how important the backward compatibility is in packages development. Unfortunately life happens and backward compatibility principle may not always be held...
In such morbid situation, creating SAS packages bundles can be an interesting solution and can save your day.
Definition: a SAS packages bundle is a zip file containing one or more SAS packages and bundle metadata file inside the zip. Such a SAS bundle can be used as a container for a "snapshot" of the current SAS packages state in the SAS environment.
The %bundlePackages() and %unbundlePackages() macros (both build atop of the %relocatePackage() macro) serves that purpose. The following use case illustrates how (and when) those macros can help.
The scenario goes as follows:
Company X keeps packages in a "central" directory /sas/packages and there are 17 different packages stored in the location.
A very important project is processed in the /projects/number42 directory. Programs and data are kept inside the location.
For their analysis The A-team is using packages ABC and XYZ located in /sas/packages directory.
The project successfully ends December 31st, 2025, and the A-team "saves" current versions of ABC and XYZ packages into bundleForProject42_20251231 bundle.
filename packages "/sas/packages";
%include packages(SPFinit.sas);
libname b "/sas/bundles";
%let date=20251231;
%bundlePackages(
bundleForProject42_&date.
, packagesList=ABC XYZ
, path=/sas/bundles
, ods=b.SHA256forProject42_&date.
)
The snippet above assigns packages fileref to /sas/packages, enables the framework (personally I'd keep those 2 lines in the autoexec), sets library b, and creates convenience macro variable date. The %bundlePackages() macro takes packages ABC and XYZ from the packages fileref and bundles them into the bundleForProject42_&date. bundle.
After execution the bundleforproject42_20251231.bundle.zip file and the SHA256forProject42_20251231.sas7bdat data set (containing the bundle's SHA256 checks sum) are stored in the /sas/bundles directory.
Some time passes and newer versions of packages ABC and XYZ are developed and installed in the central packages directory. Hopefully developers followed the backward compatibility principle when they were updating/modifying those packages, but with the bundle the A-team doesn't have to worry.
Some time later The A-team gets a request to re-run project 42 on newly delivered data.
To ensure expected behavior of ABC and XYZ the A-team extracts the bundleForProject42_20251231 bundle file from the /sas/bundles directory to a temporary location in /adhoc/for42 (they also, optionally, verify if the bundle was not modified by someone from a "hostile" B-team).
filename packages "/sas/packages";
%include packages(SPFinit.sas);
%let bndls=/sas/bundles; /* bundles location */
%let date=20251231;
/* verify bundle */
libname b "&bndls.";
data _null_;
set b.SHA256forProject42_&date.;
call symputX('bundleSHA256', bundleSHA256);
run;
%verifyPackage(
bundleForProject42_&date..bundle
, hash=&bundleSHA256.
, path=&bndls.
)
/* extrat bundle to /adhoc/for42 */
%unbundlePackages(
bundleForProject42_&date.
, path=&bndls.
, packagesPath=/adhoc/for42
, verify=1
)
Note that the .bundle suffix was added to bundle name in the %verifyPackage() macro call.
After successful unbundling the A-team appends the /adhoc/for42 path to the beginning of the packages fileref.
filename packages ("/adhoc/for42" %extendPackagesFileref());
Packages ABC and XYZ can now be loaded with their historical versions.
The A-team successfully re-runs the project.
The (Happy) End.
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.