in DXL, how to get the handle of a module that I don't open myself in the DXL script - ibm-doors

I have a DXL script that open (read or edit) modules and put them in a skip list (so that I could close them at the end)
The skip list store the module handle of each module read or edit :
if (MODIF_OTHER_MODULES)
{
modSrc = edit(modSrc_Name, false)
} else
{
modSrc = read(modSrc_Name, false)
}
put(skp_openmodule, modSrc, modSrc)
But sometimes modules are already open outside my DXL script so following check is KO :
mvSource = sourceVersion lr
modSrc_data = data mvSource
modSrc_Name = fullName(source lr)
if (null modSrc_data)
"read/edit modSrc_Name module and add module in the skip list" : OK DONE
else
"the module is already open but maybe I don't open it myself"
"so I WANT TO CHECK if module is already in the skiplist and ADD module of modSrc_data in the precedent skip list if it isn't " : I DONT KNOW HOW !
"
Is there a way to get module of modSrc_data so that it could be added in skp_openmodule if it is not already present in the list ?
I don't want to read/edit it again because I don't know in which mode it was open previously and I would prefer to avoid it because I will do it for each objet and each link !
also it would be great if I could also retrieve the information about how the module was open (read or edit)
I tried :
module (modSrc_data)
and
module(modSrc_Name)
but it doesn't work.

Not sure if this is due to the excerpt you posted, but you should always turn off the autodeclare option and ensure that you always use the correct types for your variables by either checking the DXL manual or by using alternative sources like the "undocumented perms list" . data performed on a ModuleVersion returns type Module. So you already have what you need. An alternative would be the perm bool open(ModName_ modRef). And note that the perm module does not return a Module, but a ModName_.
Also, in addition to bool isRead(Module m), bool isEdit(Module m) and bool isShare(Module m)(!!) when you really want to close modules that have been opened previously, you might want to check bool unsaved(Module m)
ModuleVersion mvSource = sourceVersion lr
Module modSrc_data = data mvSource
string modSrc_Name = fullName(source lr)
if (null modSrc_data)
print "read/edit modSrc_Name module and add module in the skip list"
else
{
print "the module is already open but maybe I don't open it myself"
if isRead (modSrc_data) then print " - read"
if isEdit (modSrc_data) then print " - edit"
if isShare (modSrc_data) then print " - shared mode"
if unsaved (modSrc_data) then print " - do not silently close me, otherwise the user might be infuriated"
}

Related

Use curried lua function as custom complete list in neovim

I'm trying to provide a curried lua function as method to call for autocomplete a command. However, it sometimes does nothing and sometimes fails with a memory segmentation error.
This is a minimal reproduction example:
Given this init.lua
vim.cmd(string.format([[set rtp=%s]], vim.fn.getcwd()))
local custom_complete = [[customlist,v:lua.require'split_later'.split_later('a b')]]
local options = { complete = custom_complete, desc = "Test to break", nargs = 1, force = true }
vim.api.nvim_create_user_command("Test", "echo <args>", options)
And this file called split_later under the correct lua/ subfolder:
local M = {}
function M.split_later(str)
print("called split")
return function()
return vim.fn.split(str)
end
end
return M
The idea is to have a generic utility that is able to produce auto-complete functions from lua, but it is not working as expected.
I found a workaround using a lookup table that stores the command name and then uses it, but I don't like it that much.

Groovy read file line by line and store it into list

I have a file called apps.txt which has three app names in it
frontendapp
authorizationservice
connectorservice*
In jenkins pipeline i want to perform some operation on them one by one so i am trying to get them in groovy list using this code -
list = readFile.readFileLineByLine("${workspace}/apps.txt").collect {it}
for (item in list) {
println "I need to perform some operations on files"
}
But getting groovy.lang.MissingPropertyException.
If i use file class like this - list = new File("${workspace}/apps.txt").collect {it} then it search for a file on Jenkins master node only and i get fileNotFoundException.
If i use list = readFile("${workspace}/apps.txt").collect {it} then list gets values character by character. How i can get app names from apps.txt inorder to perform operation on each app.
Your attempts are close, but mix things up.
Those are working ways:
def list = new File("${workspace}/apps.txt").text.readLines()
Note the .text call inbetween.
def list = readFile("${workspace}/apps.txt").readLines()
Or with the helper Jenkins provides.
Side note: .collect{it} is just .collect() - and usually is only
needed to copy a list. Since the read lines from the file are already
eagerly read, those are copies.
This work for me in a windows worker
script {
def list = readFile("filesChanged").readLines()
for(item in list){
print item
bat('type '+item)
}
}

How to rewrite URL in Yaws/Erlang

How can I access yaws file without including it's extension? Say,
www.domain.com/listen.yaws => www.domain.com/listen
I could not find any specific documentation for this from yaws documentation/appmod.
I think the question is ultimately clarified!
You can find one example of how to accomplish this in the "Arg Rewrite" section (7.1.2) of the Yaws PDF documentation. Set the variable arg_rewrite_mod in your server configuration to the name of an Erlang module supporting rewriting:
arg_rewrite_mod = my_rewriter
To support rewriting, the my_rewriter module must define and export an arg_rewrite/1 function, taking an #arg{} record as its argument:
-module(my_rewriter).
-export([arg_rewrite/1]).
-include_lib("yaws/include/yaws_api.hrl").
rewrite_pages() ->
["/listen"].
arg_rewrite(Arg) ->
Req = Arg#arg.req,
{abs_path, Path} = Req#http_request.path,
case lists:member(Path, rewrite_pages()) of
true ->
Arg#arg{req = Req#http_request{path = {abs_path, Path++".yaws"}}};
false ->
Arg
end.
The code includes yaws_api.hrl to pick up the #arg{} record definition.
The rewrite_pages/0 function returns a list of pages that must be rewritten to include ".yaws" suffixes; in this example, it's just the /listen page you mention in your question. If in arg_rewrite/1 we find the requested page in that list, we append ".yaws" to the page name and include it in a new #arg{} we return to Yaws, which then continues dispatching the request based on the new #arg{}.

sanitizing a Lua table input

Let's say I want a Lua table that will be provided from a third party, not totally reliable, from a file or other IO source.
I get the table as a string, like "{['valid'] = 10}" and I can load it as
externalTable = loadstring("return " .. txtTable)()
But this opens a breach to code injection, ie.: txtTable = os.execute('rm -rf /')
So I did this sanitizing function:
function safeLoadTable(txtTable)
txtTable = tostring(txtTable)
if (string.find(txtTable, "(", 1, true))
then return nil end
local _start = string.find(txtTable, "{", 1, true)
local _end = string.find(string.reverse(txtTable), "}", 1, true)
if (_start == nil or _end == nil)
then return nil end
txtTable = string.sub(txtTable, _start, #txtTable - _end + 1)
print("cropped to ", txtTable)
local pFunc = loadstring("return " .. txtTable)
if (pFunc) then
local _, aTable = pcall(pFunc)
return aTable
end
end
In the worst case it should return nil.
Can this be considered safe against a "regular bad-intentioned person" :)
You could run the unsafe code in a sandbox.
Here is how a simple sandbox could look in Lua 5.1 (error handling omitted for brevity):
local script = [[os.execute("rm -rf /")]]
local env = { print=print, table=table, string=string }
local f, err = loadstring(script)
if err then
-- handle syntax error
end
setfenv(f, env)
local status, err = pcall(f)
if not status then
-- handle runtime error
end
In Lua 5.2 you can load the script into it's own environment using the load function.
The result would be a runtime error returned from pcall:
attempt to index global 'os' (a nil value)
EDIT
As Lorenzo Donati pointed out in the comments this is not a complete solution to stop rogue scripts. It essentially allows you to white-list functions and tables that are approved for user scripts.
For more info about handling rogue scripts I would suggest this SO question:
Embedded Lua - timing out rogue scripts (e.g. infinite loop) - an example anyone?
I don't think it is safe. Try this:
print(safeLoadTable [[{ foo = (function() print"yahoo" end)() } ]])
EDIT
or this, for more fun:
print(safeLoadTable [[{ foo = (function() print(os.getenv "PATH") end)() } ]])
I won't suggest the alternative of replacing that os.getenv with os.execute, though. :-)
The problem is not easy to solve. Code injection avoidance is not at all simple in this case because you are executing a piece of Lua code when doing that loadstring. No simple string matching technique is really safe. The only secure way would be to implement a parser for a subset of the Lua table syntax and use that parser on the string.
BTW, even Lua team stripped off the bytecode verifier from Lua 5.2 since they discovered that it was amenable to attacks, and bytecode is a far simpler language than Lua source code.
I created sandbox.lua for exactly this purpose. It'll handle both insecure stuff as well as DOS-type attacks, assuming that your environment has access to the debug facility.
https://github.com/kikito/sandbox.lua
Note that for now it is Lua 5.1-compatible only.
Running in sandbox isn't safe, inspecting source code is not very simple. An idea: inspect bytecode!
Emmm, actually that's not very simple either, but here is a lazy implementation: http://codepad.org/mGqQ0Y8q

Create suite of interdependent Lua files without affecting the global namespace

tl;dr: What design pattern allows you to split Lua code over multiple files that need to share some information without affecting the global table?
Background
It is considered bad form to create a library in Lua where requiring the library affects the global namespace:
--> somelib.lua <--
SomeLib = { ... }
--> usercode.lua <--
require 'somelib'
print(SomeLib) -- global key created == bad
Instead, it is considered a best practice to create a library that uses local variables and then returns them for the user to assign as they see fit:
--> somelib.lua <--
local SomeLib = { ... }
return SomeLib
--> usercode.lua <--
local theLib = require 'somelib' -- consumers name lib as they wish == good
The above pattern works fine when using a single file. However, this becomes considerably harder when you have multiple files that reference each other.
Concrete Example
How can you rewrite the following suite of files so that the assertions all pass? Ideally the rewrites will leave the same files on disk and responsibilities for each file. (Rewriting by merging all code into a single file is effective, but not helpful ;)
--> test_usage.lua <--
require 'master'
assert(MASTER.Simple)
assert(MASTER.simple)
assert(MASTER.Shared)
assert(MASTER.Shared.go1)
assert(MASTER.Shared.go2)
assert(MASTER.Simple.ref1()==MASTER.Multi1)
assert(pcall(MASTER.Simple.ref2))
assert(_G.MASTER == nil) -- Does not currently pass
--> master.lua <--
MASTER = {}
require 'simple'
require 'multi'
require 'shared1'
require 'shared2'
require 'shared3'
require 'reference'
--> simple.lua <--
MASTER.Simple = {}
function MASTER:simple() end
--> multi.lua <--
MASTER.Multi1 = {}
MASTER.Multi2 = {}
--> shared1.lua <--
MASTER.Shared = {}
--> shared2.lua <--
function MASTER.Shared:go1() end
--> shared3.lua <--
function MASTER.Shared:go2() end
--> reference.lua <--
function MASTER.Simple:ref1() return MASTER.Multi1 end
function MASTER.Simple:ref2() MASTER:simple() end
Failure: Setting the Environment
I thought to solve the problem by setting the environment to my master table with a self-reference. This does not work when calling functions like require however, as they change the environment back:
--> master.lua <--
foo = "original"
local MASTER = setmetatable({foo="captured"},{__index=_G})
MASTER.MASTER = MASTER
setfenv(1,MASTER)
require 'simple'
--> simple.lua <--
print(foo) --> "original"
MASTER.Simple = {} --> attempt to index global 'MASTER' (a nil value)
You are giving master.lua two responsibilities:
It defines the common module table
It imports all of the submodules
Instead you should create a separate module for (1) and import it in all of the submodules:
--> common.lua <--
return {}
--> master.lua <--
require 'simple'
require 'multi'
require 'shared1'
require 'shared2'
require 'shared3'
require 'reference'
return require'common' -- return the common table
--> simple.lua <--
local MASTER = require'common' -- import the common table
MASTER.Simple = {}
function MASTER:simple() end
etc.
Finally, change the first line of test_usage.lua to use a local variable:
--> test_usage.lua <--
local MASTER = require'master'
...
The tests should now pass.
I have a systematic way to solve that problem. I have refactored your module in a Git repository to show you how it works: https://github.com/catwell/dont-touch-global-namespace/commit/34b390fa34931464c1dc6f32a26dc4b27d5ebd69
The idea is that you should have the sub-parts return a function that takes the main module as an argument.
If you cheat by opening the source files in master.lua, append a header and a footer and use loadstring, you can even use them unmodified (only master.lua has to be modified, but it is more complex). Personally, I prefer to keep it explicit, which is what I have done here. I don't like magic :)
EDIT: it is very close to Andrew Stark's first solution, except I patch the MASTER table directly in the sub-modules. The advantage is that you can define several things at once, like in your simple.lua, multi.lua and reference.lua files.
We can solve the problem by changing the master file to modify the environment in which all required code is run:
--> master.lua <--
local m = {} -- The actual master table
local env = getfenv(0) -- The current environment
local sandbox = { MASTER=m } -- Environment for all requires
setmetatable(sandbox,{__index=env}) -- ...also exposes read access to real env
setfenv(0,sandbox) -- Use the sandbox as the environment
-- require all files as before
setfenv(0,env) -- Restore the original environment
return m
The sandbox is an empty table that inherits values from _G but that also has a reference to the MASTER table, simulating a global from the perspective of later code. Using this sandbox as the environment causes all later requires to evaluate their "global" code in this context.
We save the real environment for later restoration, so that we don't mess with any later code that might want to actually set a global variable.
The question concerns:
Not polluting the global space when making modules.
Making modules in such a way that they might be split into multiple files, for maintenance reasons, among others.
My solution to the above problem lies in tweaking the "return as table" idiom in Lua such that instead of returning a table, you return a function that returns a table, when state needs to be passed between sub-modules.
This works well for sub-modules that are entirely dependent upon some root-module. If they are loaded independently, then they require the user to know that they need to call the module before they can use it. This is unlike every other module that has a collection of methods, ready to go from local a = require('a').
At any rate, this works like so:
--callbacks.lua a -- sub-module
return function(self)
local callbacks = {}
callbacks.StartElement = function(parser, elementName, attributes)
local res = {}
local stack = self.stack
---awesome stuff for about 150 lines...
return callbacks
end
To use it, you can...
local make_callbacks = require'callbacks'
self.callbacks = make_callbacks(self)
Or, better yet, simply call the return value of require when assigning the callback table to the parent module, like so:
self.callbacks = require'trms.xml.callbacks'(self)
Most often, I try not to do this. If I'm passing state or self between submodules, I find that I'm often doing it wrong. My internal policy is that if I'm doing something that is highly-related to another file, I might be okay. More likely, I'm putting something in the wrong spot and there is a way to do it without passing anything between modules.
The reason that I don't like this is that which I pass by table has methods and properties unseen in the file that I am working within. I'm not free to refactor the internal implementation of one of my files, without horking the others. So, I humbly suggest that this idiom is a yellow flag, but probably not a red one. :)
While this solves the problem of state-sharing without globals, it doesn't really protect the user from the accidental omission of local. If I may speak to that implied question...
The first thing that I do is remove access to the global environment from my module. Remembering that it's only available as long as I don't
reset _ENV, reseting it is the first thing that I do. This is done by packing only what is needed into a new _ENV table.
_ENV = {print = print,
pairs = pairs, --etc
}
However, constantly re-typing all of the things that I need from lua into each file is a giant, error-prone pain. To avoid this, I make one file in my module's base directory and use it as the home for all of my modules' and sub-modules' common environments. I call it _ENV.lua.
Note: I cannot use "init.lua" or any other root-module for this purpose, because I need to be able to load it from the sub-modules, which are being loaded by
the root-module, which loads the sub-modules, which are...
My abbreviated _ENV.lua file looks something like the following:
--_ENV.lua
_ENV = {
type = type, pairs = pairs, ipairs = ipairs, next = next, print =
print, require = require, io = io, table = table, string = string,
lxp = require"lxp", lfs = require"lfs",
socket = require("socket"), lpeg = require'lpeg', --etc..
}
return _ENV
With this file, I now have a common base from which to work.
All of my other modules load this first, using the following command:
_ENV = require'root_mod._ENV' --where root_mod is the base of my module.
This facility was critical for me, for two reasons. First, it keeps me
out of global space. If I see that I am missing something from the global environment _G (took me a surprisingly long time before I saw that I didn't have
tostring!), I can go back into my _ENV.lua file and add it. As
a required file, this only gets loaded one time, so having it applied
to all of my submodules is 0 calories.
Second, I find that it gives me everything that I really needed for using
the "return module as table" protocol, with only a few exceptions where "return a function that returns a table" is needed.
TL;DR: Don't return the module, set package.loaded[...] = your_module as early as possible (can still be empty), then just require the module in submodules and it will be properly shared.
The clean way to do this is to explicitly register the module and not rely on require to implicitly register it at the end. The documentation says:
require (modname)
Loads the given module. The function starts by looking into the
package.loaded table to determine whether modname is already loaded.
If it is, then require returns the value stored at
package.loaded[modname]. [This gets you the caching behavior that
every file is run only once.] Otherwise, it tries to find a loader for
the module. [And one of the searchers is looking for Lua files to run,
which gets you the usual file loading behavior.]
[…]
Once a loader is found, require calls the loader with two arguments:
modname and an extra value dependent on how it got the loader. (If the
loader came from a file, this extra value is the file name.) If the loader
returns any non-nil value [e.g. your file returns the module table],
require assigns the returned value to package.loaded[modname]. If the
loader does not return a non-nil value and has not assigned any value to
package.loaded[modname], then require assigns true to this entry.
In any case, require returns the final value of
package.loaded[modname].
(emphasis, [comments] added by me.)
With the return mymodule idiom, the caching behavior fails if you have a loop in your dependencies – the cache is updated too late. (As a result, files may be loaded several times (you may even get endless loops!) and sharing will fail.) But explicitly saying
local _M = { } -- your module, however you define / name it
package.loaded[...] = _M -- recall: require calls loader( modname, something )
-- so `...` is `modname, something` which is shortened
-- to just `modname` because only one value is used
immediately updates the cache, so that other modules can already require your module before its main chunk returned. (Of course, at that time they can only actually use what's already been defined. But that's not usually a problem.)
The package.loaded[...] = mymodule approach works in 5.1–5.3 (incl. LuaJIT).
For your example, you would adjust the start of master.lua to
1c1,2
< MASTER = {}
---
> local MASTER = {}
> package.loaded[...] = MASTER
and for all other files
0a1
> local MASTER = require "master"
and you're done.

Resources