Skip to content
Li, Xizhi edited this page Dec 7, 2017 · 40 revisions

NPL Packages

NPL Package is a special folder under npl_packages/[package_name]/. Files in it are always organized as if they are relative to the working directory. So this folder can be used as a search path directly, or zipped to a *.zip|pkg to be used as an archive file, or loaded by file module name all at the same time.

NPL package serves following purposes:

  • it provides a way to buddle and release multiple software modules to be used by someone else.
  • it can be used as additional search path for third-party plugins, which I will explain later.
  • it provides a way to allow different versions of the same file module to coexist by putting them in different npl packages in a single application. See LoadFile
  • it provides a way to install third-party modules at development time.
  • it provides a way to share big asset files (like textures, 3d models, audios) between modules, because all npl_packages share the same working directory.

Package As Search Path

Files in npl_packages/[package_name] are usually relative to the root working directory.

Therefore, developer who wants to use other people's modules can simply add npl_packages/[package_name] to global search path by calling following code:

NPL.load("npl_packages/some_test_module/")

The trick is to end with / in file name. What this function does is actually find the package folder in a number of possible locations (see next section), and then add it to the global search path. If relative path (such as ../../test/) is used, it is always relative to dev or working directory instead of the containing scripting file. By default, when NPL starts, it will always try to load the official npl_packages/main/ package. So you do not need to call NPL.load("npl_packages/main/") in order to use the rich set of open source NPL libraries.

Another way is to load via command line, such as below. See NPLCommandLine

npl loadpackage="npl_packages/paracraft/" dev="/"

How NPL Locate Packages

When your code loads a package, NPL locates the package folder given by its relative path in following order:

  • search in dev folder if specified. See NPLCommandLine.
  • search in current working directory
  • search in current executable directory
  • search recursively for 5 parent directories of the executable directory.
  • search in foldername.zip|pkg

For example, suppose:

  • you are not using a dev folder.
  • your current working directory is /home/myapp/,
  • and your executable directory is /opt/NPLRuntime/redist/bin64/,

then NPL.load("npl_packages/main/") will search following directories until one exists and add it to the search path.

  • /home/myapp/npl_packages/main/
  • /opt/NPLRuntime/redist/bin64/npl_packages/main/
  • /opt/NPLRuntime/redist/npl_packages/main/
  • /opt/NPLRuntime/npl_packages/main/
  • /opt/npl_packages/main/
  • /npl_packages/main/
  • npl_packages/main.pkg or npl_packages/main.zip
    • the zip file may contain package.npl or [anyfoldername]/package.npl, the folder containing the package.npl is used as the root directory in the zip file.
    • if packages.npl contains searchpath = true or none, file in zip archive file is treated as relative to root.
    • if packages.npl contains searchpath = false, file in zip archive file is treated as relative to the load folder, i.e. npl_package/main/.

Please note "npl_packages/" folder prefix is not mandatory, it can be any folder name, and the above locations are searched.

Why my package is not found?

NPL does not load package automatically, one must explicitly load them (except main) either in code or command line. To verify if you have successfully load a package, go to the working directory and open the log.txt file. You should see something like below:

NPL bin dir: D:\lxzsrc\ParaEngine\ParaWorld\
WorkingDir: D:\lxzsrc\ParaEngine\ParaWorld
ParaEngine Root Dir is D:/lxzsrc/ParaEngine/ParaWorld/
search path: D:/lxzsrc/npl_packages/main/
...
search path: D:/lxzsrc/npl_packages/paracraft/
...
search path: D:/lxzsrc/ParaEngine/ParaWorld/npl_packages/ParacraftBuildinMod/

When you successfully load a package, a corresponding search path showing the exact location of the loaded path is printed to log.txt. You can verify if the absolute file location is the one you are expected. If there is no search path printed, it means that no package search path can be located, you need to verify your WorkingDir and NPL bin dir are correct and you are loading with correct spelling (path ending with a /).

Please note:

  • files in WorkingDir always has higher priority than package search path.
  • files in pkg or zip file have higher priority than disk search path. But one needs to make sure you load the file after you load your package. There is one except though, if one starts the app with dev="some folder" command line, then disk search paths have higher priority than pkg or zip files.

Layered File System

One can think of package search path as a layered file system. All NPL code reference file using relative to root directory path. However the root directory contains multiple layered mount points (search paths), it will find the file from top layer all the way to the bottom layer using the same relative to root file path.

Loading File Outside the Root Directory

As we see in layered file system, all NPL scripts are defined relative to a virtual root directory. The top layer of this root directory is the application's startup/working directory. If one wants to forcibly load NPL script outside this directory, one can use absolute directory path.

  • Under windows, you need something like NPL.load("C:\\temp/my_mod/abc.npl"), please note you must use \ after : under windows, because the : is reserved for nid. In other places, / and \ are equal. and / is recommended.
  • Under linux, you can use something like NPL.load("/opt/my_mod/abc.npl").

it is NOT recommended to use absolute file path when loading file, because it breaks dev folder and package search paths. The only use case of this is perhaps loading some test files or temporary plugin code.

Loading Folder Outside the Root Directory

One can use relative or absolute file path when loading a package with NPL.load(). If relative path (such as ../../test/) is used, it is always relative to dev or working directory instead of the containing scripting file.

NPL.load("../../anotherApp/test/");

Using relative path makes the code cross-platform. But one can also use absolute path under windows like NPL.load("C:\\temp/anotherApp/test/") or under linux like NPL.load("/opt/test/").

it is NOT recommended to load folder outside the root directory in both ways. We recommend using the standard package search path without ../ prefix.

What Happened After Loading A Package

The short answer is nothing happens, because loading a package only add its folder to the global search path. You still need to load any module files in the package folder with NPL.load. For example, support you have NPL.load("npl_packages/test/") successfully loaded at '/home/myapp/npl_packages/test/' and there is module file at /home/myapp/npl_packages/test/script/any_module_folder/test.lua Then you can load it with relative file path. NPL.load("script/any_module_folder/test.lua") However, if there is a file at your working directory such as /home/myapp/script/any_module_folder/test.lua, this file will be loaded rather than the one in the global search path.

Loading folder with package.npl

By default loading folder will do nothing but find the folder in a number of locations and add it to the global search path. However, there is one exception if the folder contains a file called package.npl.

For example, suppose, npl_mod/sample_mod/package.npl is like below:

-- example of NPL.load folder with package folder configuration file
{
	-- do not add search path when loading the containing folder via NPL.load. default to true.
	searchpath = false,
	-- bootstrapper = "",
	-- main script
	main = "fileA.lua",
}

and npl_mod/sample_mod/fileA.lua is like this

local fileA = NPL.export();
function fileA:print()
   echo("fileA")
end

Then we can load the folder as below.

local fileA = NPL.load("npl_mod/sample_mod/");
echo(fileA:print())

It will not add the folder to search path because searchpath = false and it will return export object from fileA.

packages.npl Configurations

packages.npl file supports following parameters, all of which are optional.

  • searchpath: boolean: Whether to add search path when loading the containing folder via NPL.load. default to true.
  • bootstrapper: string: the bootstrapper file to use when loaded. In most cases, only application package contains this.
  • main: string: the main script file path to load when folder is loaded. This is a relative path if searchpath is false, and absolute path if searchpath is true or nil.

File Search Order

Files in current working directory are always searched first (including those in zipped archive files) before we resolve to global search path. Moreover, search path added last is actually searched first. There is one exception, if NPL is run with dev directory in its command line dev="dev_folder", NPL packages in dev_folder are loaded before zipped archive files. This allows one to use the latest source code during development.

For example:

NPL.load("npl_packages/A/")
NPL.load("npl_packages/B/")
NPL.load("test.lua");

test.lua is searched first in current working directory and any loaded archive (zip, pkg) file. If not exist, it will search in npl_packages/B/ and then in npl_packages/A/.

Usage

For package developers:

NPL packages are mostly used at development time by other developers (not end users).

i.e. If you want other developers' to use your code, you can upload your working directory to git, so that other developers can clone your project to their npl_packages/[your module name]. Package can include not only source code, but also binary asset files, like images, textures, sound, 3d models, etc.

For other developers:

Other developers should merge all used npl_packages to working directory, before releasing their software.

i.e. It is the developer's job to resolve dependencies, in case multiple versions of the same file exist among used npl_packages. At release time, it is recommended NOT to redistribute the npl_package folder, but copy/merge the content in them to the working directory, pre-compile all source code and package code and/or assets in one or multiple archive files. Please see the DeployGuide for details. However, if different versions of the same file must coexist, we can use file-based modules to distribute in separate npl_packages folders.

Where To Find NPL Packages

Each repository under NPLPackages is a valid npl_package managed by the community.

Click here for more details on NPL packages.

If one want to upload their own package here, please make an issue here, and provide links to its code.

How To Install A Package

Simply create a folder under your development's working directory, create a sub folder called npl_packages. And then run git clone from there. Like this:

cd npl_packages
git clone https://github.com/NPLPackages/main.git

See also paracraft package for another example.

File-based Modules

See LoadFile.

How to Contribute

It is NOT advised to modify or add files in the ./npl_packages folder, instead create a similar directory structure in your project's development directory if you want to add or modify package source code. If you do want to contribute to any npl packages, please fork it on github and send pull requests to its author on github.

For example, if you want to modify or add a file like ./npl_packages/main/.../ABC.lua Instead of modify it in the npl package folder, you simply create a file at the root development folder with the same directory structure like this ./.../ABC.lua. At runtime, your version of file will be loaded instead of the one in npl package folder.

When your code is mature, you may consider fork the given npl_package in another place, and merge your changed files and send the author a pull request. If the author responds fast, he or she may accept your changes and you can later get rid of your changed files in your original project.

Clone this wiki locally