RE: Displaying the entered command-line options as parsed by clibuilder
And if anyone is interested to print the cliBuilder usage in the order that you added them, try def cli = new CliBuilder(usage:'Blaa') cli.x(..) cli.a(..) cli.formatter.setOptionComparator({a,b -> 1}) cli.usage() will now print in the order added (x then a). Merlin Beedell From: Merlin Beedell Sent: Tuesday, January 16, 2024 3:42 PM To: users@groovy.apache.org Subject: Displaying the entered command-line options as parsed by clibuilder I thought this might be useful... I wanted an easy way to print the parameters passed to groovy CliBuilder. Unlike the usage() method that prints the 'how to use' (header/parameter options/footer), I just wanted to print the final parsed value set. (Perhaps something like this could be incorporated into CliBuilder's OptionAccessor - a pretty print method?) It turns out to be a one liner [for basic single args] and 1 more for additional args. For example... def cli = new CliBuilder(usage:'''Cryoserver Export to PST''', footer:''' V1.0 MGB Jul 2020.''') cli.i(longOpt:'input', args:1, required: true, argName:'filepath', type:File, 'a directory containing Cryoserver Export zip files') cli.o(longOpt:'output', args:1, required: true, argName:'filepath', type:File, 'output into this directory') cli.d(longOpt:'depth',args:1, required: false, argName:'number', type:int, defaultValue: '1', 'levels of subdirectories to traverse. Default 1.') cli.m(longOpt:'max',args:1, required: false, argName:'number', type:int, defaultValue: '5', 'Max num mails per pst. Default 5.') cli.t(longOpt:'threads',args:1, required: false, argName:'number', type:int, defaultValue: '4', 'number of threads. Default 4.') cli.w(longOpt:'wrapped', args:0, required: false, defaultValue:false, 'Include Wrapper? Default = false (strip any wrapper)') cli.x(longOpt:'filefilter', args:1, required: false, argName:'regex', defaultValue: fileMatch, "a regex to select required export files. default = $fileMatch") cli.'?'(longOpt:'help', 'help') def opts = cli.parse(['-i','b','-o','c', 'plus', 'more']) if (!opts) { //if invalid opts then it prints usage by default return } cli.options.options.each {println "-$it.option(${it.longOpt}) = ${opts[(it.option)]}"} if (opts.arguments()) {println opts.arguments()} prints (note - args are in the same order as defined): -i(input) = b -o(output) = c -d(depth) = 1 -m(max) = 5 -t(threads) = 4 -w(wrapped) = false -x(filefilter) = .* -?(help) = false [Plus, more] Merlin Beedell
Displaying the entered command-line options as parsed by clibuilder
I thought this might be useful... I wanted an easy way to print the parameters passed to groovy CliBuilder. Unlike the usage() method that prints the 'how to use' (header/parameter options/footer), I just wanted to print the final parsed value set. (Perhaps something like this could be incorporated into CliBuilder's OptionAccessor - a pretty print method?) It turns out to be a one liner [for basic single args] and 1 more for additional args. For example... def cli = new CliBuilder(usage:'''Cryoserver Export to PST''', footer:''' V1.0 MGB Jul 2020.''') cli.i(longOpt:'input', args:1, required: true, argName:'filepath', type:File, 'a directory containing Cryoserver Export zip files') cli.o(longOpt:'output', args:1, required: true, argName:'filepath', type:File, 'output into this directory') cli.d(longOpt:'depth',args:1, required: false, argName:'number', type:int, defaultValue: '1', 'levels of subdirectories to traverse. Default 1.') cli.m(longOpt:'max',args:1, required: false, argName:'number', type:int, defaultValue: '5', 'Max num mails per pst. Default 5.') cli.t(longOpt:'threads',args:1, required: false, argName:'number', type:int, defaultValue: '4', 'number of threads. Default 4.') cli.w(longOpt:'wrapped', args:0, required: false, defaultValue:false, 'Include Wrapper? Default = false (strip any wrapper)') cli.x(longOpt:'filefilter', args:1, required: false, argName:'regex', defaultValue: fileMatch, "a regex to select required export files. default = $fileMatch") cli.'?'(longOpt:'help', 'help') def opts = cli.parse(['-i','b','-o','c', 'plus', 'more']) if (!opts) { //if invalid opts then it prints usage by default return } cli.options.options.each {println "-$it.option(${it.longOpt}) = ${opts[(it.option)]}"} if (opts.arguments()) {println opts.arguments()} prints (note - args are in the same order as defined): -i(input) = b -o(output) = c -d(depth) = 1 -m(max) = 5 -t(threads) = 4 -w(wrapped) = false -x(filefilter) = .* -?(help) = false [Plus, more] Merlin Beedell
RE: Design pattern for processing a huge directory tree of files using GPars
Thank you Bob, that did work for me. Some Java syntax is new to me - like this .map(Path::toFile). Back to school again. This is standard Java, which is pretty groovy already, but I wonder if this could be (or already has been) groovy-ised in some way, e.g. to simplify the Files.walk(..).collect(..).parallelStream(). I put the filter before the collect - on the assertion that it would be more efficient to skip unnecessary files before adding to the parallel processing. In the following snippet I include a processedCount counter - and although this works, I am aware that altering things outside of the parallel process can be bad. import java.nio.file.* import java.util.stream.* long scanFolder (File directory, Pattern fileMatch) { long processedCount = 0 Files.walk(directory.toPath(), 1) //just walk the current directory, not subdirectories .filter(p -> (Files.isRegularFile(p) && p.toString().matches(fileMatch) ) ) //skip files that do not match a regex pattern .collect(Collectors.toList()) .parallelStream() .map(Path::toFile) .forEach( msgFile -> { processedCount++ } ) return processedCount } Merlin Beedell From: Bob Brown Sent: 10 May 2022 09:19 To: users@groovy.apache.org Subject: RE: Design pattern for processing a huge directory tree of files using GPars If you are able to use a modern Java implementation, you can use pure-Java streams, eg: https://stackoverflow.com/a/66044221 /// Files.walk(Paths.get("/path/to/root/directory")) // create a stream of paths .collect(Collectors.toList()) // collect paths into list to better parallize .parallelStream() // process this stream in multiple threads .filter(Files::isRegularFile) // filter out any non-files (such as directories) .map(Path::toFile) // convert Path to File object .sorted((a, b) -> Long.compare(a.lastModified(), b.lastModified())) // sort files date .limit(500) // limit processing to 500 files (optional) .forEachOrdered(f -> { // do processing here System.out.println(f); }); /// also read : https://www.airpair.com/java/posts/parallel-processing-of-io-based-data-with-java-streams Hope this helps some. BOB From: Merlin Beedell mailto:mbeed...@cryoserver.com>> Sent: Monday, 9 May 2022 8:12 PM To: users@groovy.apache.org<mailto:users@groovy.apache.org> Subject: Design pattern for processing a huge directory tree of files using GPars I am trying to process millions of files, spread over a tree of directories. At the moment I can collect the set of top level directories into a list and then process these in parallel using GPars with list processing (e.g. .eachParallel). But what would be more efficient would be a 'parallel' for the File handling routines, for example: withPool() { directory.eachFileMatchParallel (FILES, ~/($fileMatch)/) {aFile -> ... then I would be a very happy bunny! I know I could copy the list of matching files into an Array list and then use the withPool { filesArray.eachParallel { ... - but this does not seem like an efficient solution - especially if there are several hundred thousand files in a directory. What design pattern(s) might be better to consider using? Merlin Beedell
Design pattern for processing a huge directory tree of files using GPars
I am trying to process millions of files, spread over a tree of directories. At the moment I can collect the set of top level directories into a list and then process these in parallel using GPars with list processing (e.g. .eachParallel). But what would be more efficient would be a 'parallel' for the File handling routines, for example: withPool() { directory.eachFileMatchParallel (FILES, ~/($fileMatch)/) {aFile -> ... then I would be a very happy bunny! I know I could copy the list of matching files into an Array list and then use the withPool { filesArray.eachParallel { ... - but this does not seem like an efficient solution - especially if there are several hundred thousand files in a directory. What design pattern(s) might be better to consider using? Merlin Beedell
Delete empty folders in a tree
Groovy provides a File.deleteDir() method that deletes a complete tree of directories AND files. But what if I just want to delete empty directories? It would be useful if this method could take an optional parameter (e.g. Boolean - onlyEmpty = if true only delete if empty) - or perhaps even a closure returning true/false to determine the criteria on which deletion should occur - e.g. delete folder and content unless the folder contains a particular file. This simple method below will delete any empty folders below the provided File path. For performance, it is over simple, as it could skip deletes of parent folders where a child folder is not empty (hence not deleted). void clearEmptyDirectories(File aDir) { def emptyDirs = [] aDir.eachDirRecurse { testDir -> emptyDirs << testDir } // reverse so that we do the deepest folders first // but do not delete a folder if it is not empty emptyDirs.reverseEach { it.delete() } } Merlin Beedell
RE: Self logging scripts
This line should have been like this: new File(getClass().protectionDomain.codeSource.location.path).name.toLowerCase().replace('.groovy', '') Merlin Beedell From: Merlin Beedell Sent: 26 January 2021 3:33 PM To: users@groovy.apache.org Subject: Self logging scripts Hi all, I am successfully using the following chunk of groovy code at the top of various console scripts in order to preserve the various stdout/strerr output to a log file - as well as on the console. There are a couple of points. First it uses SystemOutputInterceptor - but this class appears to be depreciated. Is there something coming to replace it? Second, I would like to be able to print the command line as entered by the user who provoked the script. The nearest I could get was to print the args list (as below). Is there a simple way of obtaining the actual command entered by the user so it can be included with the log? I was hoping the CliBuilder might have a pretty print feature, but I can't see one. import groovy.ui.SystemOutputInterceptor def dateString = new Date().format('MMMdd-HHmmss') String getScriptFileName() { new File(getClass().protectionDomain.codeSource.location.path).name.toLowerCase().replace(/\.groovy/, '') } new File('./logs').mkdir() def logOutput = new PrintWriter(new File("./logs/${getScriptFileName()}-${dateString}.log")) def myLoger = new SystemOutputInterceptor( { Object... args -> logOutput << args[-1]; logOutput.flush(); true } ) myLoger.start() if (args) { print "Parameters provided:" args.each {print " " + it} println "" } println "this is printed to the console window and to the log file - like a 'tee' feature. Really useful" Merlin Beedell
Self logging scripts
Hi all, I am successfully using the following chunk of groovy code at the top of various console scripts in order to preserve the various stdout/strerr output to a log file - as well as on the console. There are a couple of points. First it uses SystemOutputInterceptor - but this class appears to be depreciated. Is there something coming to replace it? Second, I would like to be able to print the command line as entered by the user who provoked the script. The nearest I could get was to print the args list (as below). Is there a simple way of obtaining the actual command entered by the user so it can be included with the log? I was hoping the CliBuilder might have a pretty print feature, but I can't see one. import groovy.ui.SystemOutputInterceptor def dateString = new Date().format('MMMdd-HHmmss') String getScriptFileName() { new File(getClass().protectionDomain.codeSource.location.path).name.toLowerCase().replace(/\.groovy/, '') } new File('./logs').mkdir() def logOutput = new PrintWriter(new File("./logs/${getScriptFileName()}-${dateString}.log")) def myLoger = new SystemOutputInterceptor( { Object... args -> logOutput << args[-1]; logOutput.flush(); true } ) myLoger.start() if (args) { print "Parameters provided:" args.each {print " " + it} println "" } println "this is printed to the console window and to the log file - like a 'tee' feature. Really useful" Merlin Beedell 0800 280 0525 / +44 (0)207 045 0520 DDI: +44 (0)207 045 0528 Mob: +44 (0)7876 226865 Cryoserver: A focused, flexible email archive delivered by experts
RE: Defining a global variable
I thought that implicit variables would overcome this. Not an elegant solution - as you are simply declaring variables on the fly without an explicit data type or even a 'def'. Having said, it is generally safer to explicitly list the parameters used in a method when used in this context (e.g. in a script without an explicit class declaration to mop up this case). And as for 'global' - I sure wish the word 'global' was used instead of 'static'. It just kinda makes more sense to me! //=== test='' //implicit declaration of a variable void func() { println(test) } test = 'hello' func() //=== Or just //=== void func() { println(test) } test = 'hello' func() //=== Merlin Beedell -Original Message- From: MG Sent: 15 October 2020 6:21 PM To: users@groovy.apache.org; Jochen Theodorou Subject: Re: Defining a global variable On 15/10/2020 18:27, Jochen Theodorou wrote: > well.. even scripts are first compiled into a class before the class > is then executed. Groovy has no interpreter Which, I think, is a lesser known fact, and quite surprising to people who perceive Groovy just under its "script language" aspect ;-)
RE: 3.0.x Windows installers released
Keegan, Thanks very much for that reply. I can’t really comment on the 32/64 bit debate. I just think that apps installed in ProgFiles32 are ‘old’ – which I am sure that Groovy would not wish to be thought to be. Just read your recent update: I now understand the “groovy …”.execute() thing better, I may evolve my scripts to use the Script Engine and move away from returning exit statuses. But nevertheless, there may be a case to include an ‘option’ in the installer for binary wrappers. As for the scriptom thing – I guess it does not need to evolve as the Windows COM objects have equally not changed for many years. But COM enabled things very much still exist and will probably continue to do so for a good while longer – but a time appears to be coming when Windows becomes a side project to Linux (as seen from the WSL efforts). And I think that Office Automation tooling is shifting to newer APIs and web services (like OAuth and ‘Graph’). So if there was a simple way to download and install Jacob/scriptom as a separate thing, that might help for the few that still use it! Merlin Beedell From: Keegan Witt Sent: 29 September 2020 7:33 AM To: users@groovy.apache.org Subject: Re: 3.0.x Windows installers released 1. That's correct. There were a few discussions about why I thought we should do this. Here's a short summary: Most of the modules included you can just use @grab for anyway, the few others where that wouldn't apply (GroovyServ, Grengine) seemed low usage. Scriptom was the only other one in this category that I've heard folks actually use. But multiple of the installed extras hadn't been updated in years (and some never will). It's been 10 1/2 years since the last Scriptom release. I know Scriptom is specific to Windows, but I also thought it'd be good to be somewhat consistent with the environment provided between platforms, which would help folks writing scripts targeting different platforms have some consistency. 2. I opened a PR to update the installer links (https://github.com/apache/groovy-website/pull/25). 3. Yes, as noted in the 3.0 announcement email, when the WiX version replaced the NSIS version (when 3.0 first released), the NSIS version should be uninstalled before installing the new version. 4. There are no native binaries included anymore, so there's nothing x86 or x64 specific about it. One of the things I didn't like about how the old installer worked is it would detect your current Java (from JAVA_HOME if I recall correctly) and those would be the binaries copied over. But this seemed a fragile way to do it to me, since you might have several JDKs installed, and on different architectures. There also wasn't really any reason to have 64 bit binaries in my view, since they're just wrappers for calling java.exe and will never need so much memory that they'd benefit from being 64 bit. 5. This kept the installer logic simple. I'm not sure the best practice about the installation directory when the thing being installed is platform independent. I think I should be able to use the variable for the 64 bit program files directory if available, if you think that'd be better. It seemed somewhat an arbitrary choice. 6. (the question about .bat) I think this is related to the known issue with needing vbs files to have the appropriate file association (https://github.com/groovy/groovy-wix/issues/2). I've been trying to find a better solution for this, without needing to have something as heavy-weight as the native binaries we used to use, which have logic about JAVA_HOME, etc. I haven't found a better solution yet, I may have to revive the native binaries (or do something similar). I've documented my investigations in that issue. I also mention there how you can check and fix your file associations there. 7. (the question about execute) I don't quite understand this question. The "execute" thing you're showing is a feature of the JDK. GroovyScriptEngine is included in Groovy and there's no reason you shouldn't be able to use this instead if you wish. A bit of a discussion for the dev mailing list I suppose, but what do we consider the official position on Scriptom? Should it be considered deprecated? We copied the stuff over from Codehaus after the shutdown, but it hasn't been touched since (and I think hadn't been touched in a while even before the move). If it's something we want to continue to support, I think we need to do some updates, like updating to the latest Jacob. Some questions I'd have if it were to be revived (bearing in mind I'm not really familiar with these features): 1. Should we drop the Office modules? Or if not, we might need to update for newer Office versions. 2. Should the IE6 module be dropped? IE6 is pretty dead at this point. I'm willing to reconsider the decision on including Scriptom, but not until we have a clear position on its maintenance status. I'd
3.0.x Windows installers released
Hi Groovy magic workers, I notice that the Windows Installer has changed quite a lot recently. It is nice and quick and the UI is simple. However: things I note in this release: 1. The supplementary extras (e.g. Jacob / scriptom) are not included at all, not even as a custom install. Not sure how to include these separately, other than to copy-paste from an older release. [I use scriptom to query the Windows Services list to start/stop/query various services]. 2. The Windows 3.0.4 installer and 3.0.5 releases are not yet on the ‘groovy-lang.org’ download site. 3. My Environment PATH variable appears to have 2 entries pointing to the new groovy home. Perhaps it edits the previous entry and then adds the new one as well. 4. It does not supply separate 64-bit executables that can be exchanged with the 32-bit executables, which might relate to the next item… 5. It defaults the install under program files (x86) – suggesting a 32-bit implementation only. Only the ‘custom’ option allows it to be put somewhere else. I then noticed that if I execute this in groovysh or in the groovyConsole: “groovy -v”.execute().waitForProcessOutput(System.out, System.err) Exception thrown java.io.IOException: Cannot run program "groovy": CreateProcess error=2, The system cannot find the file specified at ConsoleScript5.run(ConsoleScript5:1) Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified But this works “groovy.bat -v”.execute().waitForProcessOutput(System.out, System.err) Groovy Version: 3.0.3 JVM: 1.8.0_162 Vendor: Oracle Corporation OS: Windows 10 Does this suggest that the installed groovy is 32-bit when my computer and JDK are both 64-bit? My older groovy installs (going back to 2.0.4) would all work. PS – Why call groovy using “execute” rather than GroovyScriptEngine? Well some of these called scripts use System.exit (error-number) and if I use the ScriptEngine or similar, it causes my script to exit as well! Merlin Beedell 0800 280 0525 / +44 (0)207 045 0520 DDI: +44 (0)207 045 0528 Mob: +44 (0)7876 226865 Cryoserver: A focused, flexible email archive delivered by experts From: Guillaume Laforge Sent: 23 July 2020 12:51 PM To: users@groovy.apache.org; Paul King Subject: Re: [ANNOUNCE] Groovy 2.4.20, 2.5.13, and 3.0.5 Windows installers released Combo! Le jeu. 23 juil. 2020 à 12:13, Paul King mailto:pa...@asert.com.au>> a écrit : Nice! On Thu, Jul 23, 2020 at 3:07 PM Keegan Witt mailto:keeganw...@gmail.com>> wrote: 2.4.20: https://bintray.com/groovy/Distributions/download_file?file_path=groovy-2.4.20.msi 2.5.13: https://bintray.com/groovy/Distributions/download_file?file_path=groovy-2.5.13.msi 3.0.5: https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.5.msi -Keegan
File counting methods
This might not be a suitable question for the groovy users, but I am using it in a groovy script, so thought it might solicit some useful feedback and alternate ideas. In Java's NIO there are a couple of ways to walk the tree of files in order to return a file count. There must be lots of ways! I don't know Groovy has a better built in method - but I could not see it. This one should be the fastest, using concurrent processes. However, if the set of files changes during the count it errors. I have no idea how to catch and ignore that error. long fileCountV2(Path dir) { return Files.walk(dir) .parallel() .filter(p -> !p.toFile().isDirectory()) .count(); } This one works regardless of any file changes, and uses a Stream for low memory overhead. But it could do with concurrency to speed it up, but I really cannot figure how to GPARS this for performance. This script did once fail with "too many files open" error on Linux (and a directory with 200,000+ files). I can't determine how - no files are actually opened! long fileCount(Path dir) { long i = 0 try { Files.newDirectoryStream(dir).each {i++} } catch (e) { println (e) } return i } Merlin Beedell
Help! - GPARS with eachFile & database concurrency
Hi wonderful Groovy team, I am really struggling to determine a "straight forward" groovy way to amend a simple linear script into one using some level of concurrency. I cannot find suitable examples for the task at hand, namely: I use derby database to collect data from email files on a server. So 1. I walk the directory tree using a mix of eachDirRecurse and eachFileMatch. 2. High level directories are names of mailboxes - so I add these to the database, first checking that the mailbox is not already in the db. int addUser(def Username) { def res = sql.firstRow ("select id from user_info where user_name = ?", [Username]) if (!res) { def keys = sql.executeInsert("insert into user_info (user_name) " + "VALUES (?)", [Username]) return keys[0][0] //return the auto-generated row id number from the db } else { return res.id } } I guess I could just insert the data - and if it errors with 'duplicate key' then I know it already exists, but then I would still need to obtain the row ID to return back to the caller. 1. And when I find a file that is an email type, I read it line-by-line until I obtain the required header details (date: / subject: / from: / message-id: ) or a blank line ( end of headers). I add these details to the database (again, checking that the item is not already there). So I currently use a single SQL connection and a simple loop over the directory and files - its simple and works well. But as there are several million files, I really need to use multiple threads. I read that a "DataSource" is a way to pool Database connections. I just cant see how this works - does it just dynamically create connections on demand [def sql = new Sql(mydatasource)], and when the 'sql' variable is garbage collected, the connection is returned to the 'pool'? Is each sql instance "thread safe" from each other? And are prepared statements also in the 'pool' - so the sql statements are not parsed every time regardless of the connection used? As for concurrency... I have previously used, in a basic sense, threads. And then I looked at GPARS, which seems to be the appropriate way to go. So how might the 'eachDirRecurse' and 'eachFileMatch' be altered to a GPARs "withPool" collection loop? How should each loop call the sql routines so they are thread safe - presumably by creating sql connection from datasource (pool) > do sql > done. The withPool will create upto cpu-count + 1 - but should I use more with this type of process logic? I assume that I could use the "withPool" within another "withPool", so that I can process [the pool count] some mailboxes in concurrently and also the files within each mailbox in parallel. Is there some metric that determines how effective concurrent disk actions (just reading in this case) can be - e.g. so I could determine a sensible limit on the number of [email] files being read at the same time. What monitoring method would help? I don't think I need to use "actors" here, nor the "dataflow" feature. Even after reading Groovy in Action (2ed), it is still not really clear how to proceed. I have googled a lot, but still cannot map my ideas into a GPARS solution. So I thought I should ask the experts - the groovy community - for some suggestions or appropriate reading material. The nearest I have found to a useful template on this topic is https://stackoverflow.com/questions/35702351/concurrent-parallel-database-queries-using-groovy But I just cannot see how or why the db connection pool interacts with the GPARs so that the same connection is not grabbed by each concurrent process. Yours, hopefully, Merlin Beedell
RE: New Groovy Windows installer
I was a bit confused, as WIX is a web site design and hosting service: www.wix.com<http://www.wix.com>. But now I see your link, and it is WiX Toolset – “The most powerful set of tools available to create your Windows installation experience.” That makes more sense. Though it’s a shame that a multi-platform Java based installer could not be used (if such a thing exists). Merlin Beedell From: Keegan Witt Sent: 11 February 2019 2:24 AM To: users@groovy.apache.org Subject: New Groovy Windows installer I'm working on a new installer<https://github.com/keeganwitt/groovy-wix> for Windows using WIX<http://wixtoolset.org/> to create an MSI installer, which should be more robust for things like altering environment variables and make it easier to do corporate installations. I'm a total noob when it comes to Windows Installer and WIX, so I'm sure I've done some dumb things, but I hacked together a basic working installer this weekend. I've put the initial version of the installer here<https://www.dropbox.com/sh/w2giakqb2jcc82e/AAB_gqvCvzOU1t-2dRlV4yBoa?dl=0>. Your feedback is appreciated. Some things I'm still thinking about or working on: * The start menu shortcuts for documentation don't go into a subfolder, I'm not sure why. * Heat will generate new GUIDs for the binaries and docs folders every time the project is built -- I'm not sure if that's the correct thing to do. * Would you ever want to set GROOVY_HOME without adding to PATH? Or add to PATH without setting GROOVY_HOME? Currently the installer groups these together in a single feature. * We should use registry entries to remember which features the user selected to install, so those are automatically selected during upgrades. * Desktop shortcuts. * Quick launch shortcuts. I don't think people use these much anymore, but I can throw them in -- maybe disabled by default? * Should I create an exe version of the installer as well as the msi? -Keegan
RE: Groovy file associations on Windows
I use Scriptom – for registering and managing Windows Services (mostly). I believe that MS are moving away from the COM model – but I am sure it will be around for a while yet. As such it will not change much – and hence the ScriptOM utility is unlikely to need changing either. Here is an example: org.codehaus.groovy.scriptom.Scriptom.inApartment { def locator = new org.codehaus.groovy.scriptom.ActiveXObject('WbemScripting.SWbemLocator') def services = locator.ConnectServer('.') < /* a test to list all cryo services with their dependencies */ if (testOnly) { for(process in services.ExecQuery("SELECT Name FROM Win32_Service where (displayname like 'cryo%') and StartMode != 'Disabled'", 'WQL', wbemFlagForwardOnly)) { println process.Name() for (depServ in services.ExecQuery("Associators of {Win32_Service.Name='" + process.Name() + "'} Where AssocClass=Win32_DependentService Role=Dependent")) { println "\tDep: ${depServ.DisplayName} state: ${depServ.State}" } for (depServ in services.ExecQuery("Associators of {Win32_Service.Name='" + process.Name() + "'} Where AssocClass=Win32_DependentService Role=Antecedent")) { println "\tAsc: ${depServ.DisplayName} state: ${depServ.State}" } } } } Merlin Beedell 0800 280 0525 / +44 (0)207 045 0520 DDI: +44 (0)207 045 0528 Mob: +44 (0)7876 226865 Cryoserver: A focused, flexible email archive delivered by experts From: Keegan Witt Sent: 11 February 2019 2:24 AM To: users@groovy.apache.org Subject: Groovy file associations on Windows In addition to removing projects that are no longer developed from the Groovy Windows installer (Gpars, Gaelyk, Scriptom, EasyB, Gant, GMock), I'm considering removing the exe files from groovy-native-launcher<https://github.com/groovy/groovy-native-launcher>. These haven't been compiled in quite a while and are just another thing to maintain. As I see it, there are two primary benefits these provide. 1. Provide a way to create file associations so you can double click a Groovy file, or run myFile.groovy instead of groovy myFile.groovy. 2. Hide the command window when launching GroovyConsole. For #2, I can work around this with a VBScript file (or NirCmd). #1 doesn't have a good way to solve other than the current native binary solution since Launch4J doesn't support variable expansion<https://sourceforge.net/p/launch4j/bugs/162/>. My question is, do many folks need this functionality? It's something I've never personally used. Please weigh in with your thoughts. -Keegan
Advent of Code challenges
There is an interesting web with a daily challenge throughout advent - http://adventofcode.com . Perhaps groovy enthusiasts could show their solutions for each challenge? My son (15) has learnt a variety of programming techniques - like linked lists - in order to answer the challenges. He is using JavaScript and Python, as these are taught at school. Merlin Beedell
RE: [DISCUSS] Groovy 2.6 potential retirement to focus on Groovy 3.0
I see a monthly release of the 2.5x product – but nothing similar for version 3. What might be happening in the V3 world? Given the license terms change under JDK 11, will the main target be OpenJDK? Merlin Beedell From: Paul King Sent: 23 June 2018 2:53 AM To: users@groovy.apache.org Subject: Re: [DISCUSS] Groovy 2.6 potential retirement to focus on Groovy 3.0 There was overwhelming support to drop 2.6 to focus on 3.0 and mixed feedback on whether to do one more 2.6 alpha release or not. So, I'll go ahead and do one more 2.6 alpha release - quite possibly much less work than further discussions and it gives us a clean end point which I am highly in favour of to reduce subsequent discussions about what exactly was in the last alpha release. We aren't planning to delete the branch - so it's still around if we need some further emergency regression fixes down the track, but we aren't planning to do any merges, so it will start to go out of sync with other branches. So even if you have an "emergency fix" for that branch, we'd encourage you to have a discussion on the mailing list before creating PRs against that branch. Cheers, Paul. On Sat, Jun 16, 2018 at 8:55 AM Robert Stagner mailto:restag...@gmail.com>> wrote: option #2 for me On Wed, Jun 13, 2018 at 12:06 AM Paul King mailto:pa...@asert.com.au>> wrote: Hi everyone, There was some discussion at gr8conf about how to speed up delivery of Groovy 3.0. Some of that discussion was around the scope of what we want to include and have yet to complete in 3.0 but I won't discuss that right now. One of the other discussion points was Groovy around 2.6. As many of you know, we have released alpha versions of Groovy 2.6. That version is a backport of most but not all of Groovy 3.0 to JDK7 including the Parrot parser (though it isn't enabled by default). The purpose of this version has always been to assist people/projects wanting to use the Parrot parser but who might be stuck on JDK7. So in some sense it is an intermediate version to assist with porting towards Groovy 3.0. While that is still a noble goal in theory, in practice, many of our users are already on JDK8 and we have limited resources to work on many potential areas. With that in mind, we'd like to understand the preferences in our user base for the following two options: Option 1: please continue releasing the best possible 2.6 even if that slows down the final release of Groovy 3.0 and delays further work on better support for JDK9+. Option 2: please release one more alpha of 2.6 over the next month or so which will become the best version to use to assist porting for users stuck on JDK7 and then focus on 3.0. The 2.6 branch will essentially be retired though we will consider PRs from the community for critical fixes. Feedback welcome. Cheers, Paul.
JDK 10: Use of var over def?
I see that the newly release JDK 10 now supports the "var" declaration for local variables where the type can clearly be inferred from its initialiser: http://openjdk.java.net/jeps/286 I note that Groovy's "def" syntax (among others) was mentioned but rejected. Would Groovy move to support this syntax in the same way (support 'var' only for Type Safe inferred declarations) or as a general alias to the "def" keyword? JDK 10 also has support for "docker" containers. The ecosystem has certainly shifted! Merlin Beedell
RE: Scriptom
I think that MS are trying to move away from the COM / DCOM model - and I found it quite difficult to locate the documentation on the basic VBA type model objects properties and methods for Outlook (as used by Scriptom). The MSDN kept directing me to other APIs, like this: https://docs.microsoft.com/en-us/office/dev/add-ins/excel/excel-add-ins-overview?product=excel This was the sort of thing that I was doing: org.codehaus.groovy.scriptom.Scriptom.inApartment { def OutApp = new org.codehaus.groovy.scriptom.ActiveXObject("Outlook.Application") def myNameSpace = OutApp.GetNameSpace("MAPI") //println myNameSpace.Folders.Count def OutMail = OutApp.CreateItem(0) OutMail.to = "m...@blaa.com" OutMail.CC = "" OutMail.BCC = "" OutMail.Subject = "This is the Subject line" OutMail.Body = "Hi there" OutMail.Send() OutMail = null OutApp = null } Merlin Beedell 0800 280 0525 / +44 (0)207 045 0520 DDI: +44 (0)207 045 0528 Mob: +44 (0)7876 226865 Cryoserver: A focused, flexible email archive delivered by experts -Original Message- From: vlkodlak [mailto:sedivy.vlkod...@gmail.com] Sent: 18 December 2017 00:53 To: us...@groovy.incubator.apache.org Subject: Re: Scriptom Hi, I used scriptom in the past and it was a really great library. Is there any hope that it will be woken up / reborn? And is / will there be some alternative on Mac? I'd like to control MS app via Groovy ... Thanks Tomas -- Sent from: http://groovy.329449.n5.nabble.com/Groovy-Users-f329450.html
Getting Methods/Properties of objects under "Scriptom"
I am trying to analyse a large chunk of emails in Outlook. I thought that I could re-write my VBA script using Groovy with "scriptom" to access the COM objects - and indeed it works. Yippee! So I can send an email and query the folder tree etc. However, I am a curious person, and sometime would like to "query" the methods and properties of an Object - and the "listMnP (Object)" [see below] works nicely for Java objects. This often helps when I am trying to match the documentation that I can find on Google, to the various objects that I am accessing. However, I get a "Can't map name to dispid: metaClass" error - which is probably quite understandable. Is it possible to query the Methods and Properties of a dynamic object in any way? org.codehaus.groovy.scriptom.Scriptom.inApartment { def OutApp = new org.codehaus.groovy.scriptom.ActiveXObject("Outlook.Application") def myNameSpace = OutApp.GetNameSpace("MAPI") println myNameSpace.Folders.Count def myFolder = myNameSpace.Folders.GetFirst() println myFolder.name listMnP myFolder /// this should cause the object "myFolder" to list its Methods and Properties - but it errors. def OutMail = OutApp.CreateItem(0) OutMail.to = "an email address!!" OutMail.CC = "" OutMail.BCC = "" OutMail.Subject = "This is the Subject line" OutMail.Body = "Hi there" OutMail.Send() OutMail = null OutApp = null } / end void listMnP (def thing) { println " >> Methods of ${thing.class} >>" thing.metaClass.methods.each { method -> println "$method.name -> $method.parameterTypes" } println " >> Properties >>" thing.metaClass.properties.each { prop -> print "$prop.name -> " try {println thing[prop.name]} catch (Exception e) {println "-NoValue-"} } try {println "Class Loader: ${thing.class.classLoader}"} catch (e) {println "No Class Loader"} } == When run the "List Methods and Properties" function is not effective === PS C:\opt\groovy\OutlookScripts> groovy .\scanMailbox.groovy 3 Online Archive - mbeed...@cryoserver.com >> Methods of class org.codehaus.groovy.scriptom.ActiveXObject >> Caught: com.jacob.com.ComFailException: Can't map name to dispid: metaClass com.jacob.com.ComFailException: Can't map name to dispid: metaClass at com.jacob.com.Dispatch.invokev(Native Method) at com.jacob.com.Dispatch.invokev(Dispatch.java:858) at com.jacob.com.Dispatch.get(Dispatch.java:1258) at com.jacob.activeX.ActiveXComponent.getProperty(ActiveXComponent.java:171) at scanMailbox.listMnP(scanMailbox.groovy:61) at scanMailbox$_run_closure2.doCall(scanMailbox.groovy:45) at scanMailbox$_run_closure2.doCall(scanMailbox.groovy) at scanMailbox.run(scanMailbox.groovy:37) Merlin Beedell
RE: Use of SystemOutputInterceptor with different groovy versions
Perfect – that works a treat. I thought I needed to overload the closure – specifying 2 closures, one with 1 parameter and another with 2. But I don’t think that is possible. Your solution is simple and effective – and now I can see how to use varags too. I use it an all my critical scripts, as it is so useful. It replicates the ‘tee’ command in Linux. We do not use many bash or bat scripts any more, just groovy scripts. And now they get logged to file and screen when they run without any fancy loggers. I don’t know if [the apache groovy dev team] might modify the documentation accordingly for this (and any other class) to cater for different Groovy versions. Merlin From: Paul King [mailto:pa...@asert.com.au] Sent: 10 November 2017 01:06 To: users@groovy.apache.org Subject: Re: Use of SystemOutputInterceptor with different groovy versions I guess we regarded that class as somewhat internal when we made that change. You could use: myLogger = new SystemOutputInterceptor({ Object... args -> logOutput << args[-1]; logOutput.flush(); true }) Cheers, Paul. On Fri, Nov 10, 2017 at 4:15 AM, Merlin Beedell <mbeed...@cryoserver.com<mailto:mbeed...@cryoserver.com>> wrote: I also noted that the following code would work just fine in recent Groovy version, but not in older. The idea is to intercept the stdout (System.out) so any output can be logged to a text file as well as to the console [really rather handy!]. import groovy.ui.SystemOutputInterceptor dateString = new Date().format("MMMdd-HHmmss") logOutput = new PrintWriter(new File("./","scriptLog_" + dateString +".log")) //log into the current directory myLoger = new SystemOutputInterceptor( {Integer i, String s -> logOutput << s; logOutput.flush(); true } ) myLoger.start() In older groovy versions, it seems that the Integer parameter is not passed to the closure (and the ‘start’ method is not required either): myLoger = new SystemOutputInterceptor( {Integer i, String s -> logOutput << s; logOutput.flush(); true } ) myLoger.start() But I can’t think how I can specify this code so it works for all versions of Groovy. This is the error if it is wrong (here under Groovy 2.0.5): Caught: groovy.lang.MissingMethodException: No signature of method: test$_run_closure2.doCall() is applicable for argument types: (java.lang.Integer, java.lang.String) values: [0, Hello world] Possible solutions: doCall(java.lang.String), findAll(), findAll() It is as though I need to be able to provide two closure definitions – one with and one without the Integer parameter. Any ideas? Merlin
Use of SystemOutputInterceptor with different groovy versions
I also noted that the following code would work just fine in recent Groovy version, but not in older. The idea is to intercept the stdout (System.out) so any output can be logged to a text file as well as to the console [really rather handy!]. import groovy.ui.SystemOutputInterceptor dateString = new Date().format("MMMdd-HHmmss") logOutput = new PrintWriter(new File("./","scriptLog_" + dateString +".log")) //log into the current directory myLoger = new SystemOutputInterceptor( {Integer i, String s -> logOutput << s; logOutput.flush(); true } ) myLoger.start() In older groovy versions, it seems that the Integer parameter is not passed to the closure (and the 'start' method is not required either): myLoger = new SystemOutputInterceptor( {Integer i, String s -> logOutput << s; logOutput.flush(); true } ) myLoger.start() But I can't think how I can specify this code so it works for all versions of Groovy. This is the error if it is wrong (here under Groovy 2.0.5): Caught: groovy.lang.MissingMethodException: No signature of method: test$_run_closure2.doCall() is applicable for argument types: (java.lang.Integer, java.lang.String) values: [0, Hello world] Possible solutions: doCall(java.lang.String), findAll(), findAll() It is as though I need to be able to provide two closure definitions - one with and one without the Integer parameter. Any ideas? Merlin
RE: Slashy strings in GroovyConsole
My preference is to use File (or Path) object whenever dealing with files – and then ONLY using forward slashes. So for your request: def scriptDir = /C:\Folder1\My Documents\Folder2\Version\etc\/ becomes def scriptDir = new File("C:/Folder1/My Documents/Folder2/Version/etc") or (if you really wanted the path as a string) def scriptDir = new File("C:/Folder1/My Documents/Folder2/Version/etc").absolutePath I agree that copy-pasting file paths from File Explorer and then twiddling the slash direction is a bit tedious – but better than figuring out all that escaping! I dare say that using a File object has overheads – but at least you can test if the file or directory exists. Iterate over the files etc. etc. Adding pieces of a path or path and file name together, again use the File class: def myScript = new File("C:/Folder1/My Scripts", "Script1.groovy") def myScript = new File(scriptDir, "Script1.groovy") It saves getting the System.properties['file.separator'] – and you can even ignore the drive letter (if it is on the current disk). def myScript = new File("/Folder1/My Scripts", "Script1.groovy") And yes – I use groovy rather a lot on Windows. Merlin Beedell Cryoserver: A focused, flexible email archive delivered by experts From: Joe Wolf [mailto:joew...@gmail.com] Sent: 14 June 2017 14:53 To: users@groovy.apache.org; Paul King <pa...@asert.com.au> Subject: Re: Slashy strings in GroovyConsole Also be careful when using slashy Strings with path names that start with a lowercase "u" They'll get interpreted as a unicode character escape, e.g. /c:\users/ --> TokenStreamIOException: Did not find four digit hex character code. (BTW, I'm glad to see there are other GroovyConsole users on Windows out there) -Joe On Wed, Jun 14, 2017 at 6:32 AM, Paul King <pa...@asert.com.au<mailto:pa...@asert.com.au>> wrote: What bo zhang said or use dollar slashy string. Cheers, Paul. On Wed, Jun 14, 2017 at 7:37 PM, bo zhang <zhangbo...@gmail.com<mailto:zhangbo...@gmail.com>> wrote: def scriptDir = /C:\Folder1\My Documents\Folder2\Version\etc\// note the last slash. \/ is escaping / On Wed, Jun 14, 2017 at 4:44 PM, Dmytro Shyshchenko <shysche...@gmail.com<mailto:shysche...@gmail.com>> wrote: Long time ago I was using slashy strings in my groovy scripts for the paths on Windows. Somehting like this: def scriptDir = /C:\Folder1\My Documents\Folder2\Version\etc\/ However in the recent versions, like 2.3.6 or 2.4.11, I can no longer execute those scripts via a GroovyConsole. It always gave me an error pointing to the last charecter of the script. Like this: unexpected char: 0x at line: 19, column: 13 which was a bit misleading... When I change the paths to a "normal" srtings, everything works fine, as it was before. def scriptDir = "C:\\Folder1\\My Documents\\Folder2\\Version\\etc\\" Is it a bug? Shall I report it? [https://www.cryoserver.com/wp-content/uploads/2017/03/ISO-logo-signature.jpg] [https://www.cryoserver.com/wp-content/uploads/2017/03/softech-signature.png] [https://www.cryoserver.com/wp-content/uploads/2017/03/ITE-signature.png] FCS (UK) Limited is registered in England & Wales, Registration Number: 5940018 - Registered Address: Wigglesworth House, 69 Southwark Bridge Road, London SE1 9HH Disclaimer: This e-mail contains proprietary information, some or all of which may be legally privileged and is for the intended recipient only and the information in it are provided in confidence and may not be disclosed to any third party or used for any other purpose without the express permission of FCS (UK) Ltd. If an addressing or transmission error has misdirected this e-mail, please notify the author by replying. If you are not the intended recipient you should not use, disclose, distribute, copy, print or relay on this e-mail. The views expressed in this communication are not necessarily the views held by FCS (UK) Limited.
gpars for calculating directory content size
I see that groovy has a handy method to return the sum of file & sub-directory sizes in a directory: new File('sample').directorySize() But I would be interested to see if the underlying code uses gpars - on the assumption that the computation would be faster if sub-directories are found (the sum of each being performed in parallel). Actually - my interest is more in seeing a useful(?) example of gpars! Merlin Beedell [https://www.cryoserver.com/wp-content/uploads/2017/03/ISO-logo-signature.jpg] [https://www.cryoserver.com/wp-content/uploads/2017/03/softech-signature.png] [https://www.cryoserver.com/wp-content/uploads/2017/03/ITE-signature.png] FCS (UK) Limited is registered in England & Wales, Registration Number: 5940018 - Registered Address: Wigglesworth House, 69 Southwark Bridge Road, London SE1 9HH Disclaimer: This e-mail contains proprietary information, some or all of which may be legally privileged and is for the intended recipient only and the information in it are provided in confidence and may not be disclosed to any third party or used for any other purpose without the express permission of FCS (UK) Ltd. If an addressing or transmission error has misdirected this e-mail, please notify the author by replying. If you are not the intended recipient you should not use, disclose, distribute, copy, print or relay on this e-mail. The views expressed in this communication are not necessarily the views held by FCS (UK) Limited.
Groovy Documentation query
Before Groovy became an Apache project, I think the web and documentation was created and maintained on an Atlassian Confluence service? What platform hosts this now? I can't see any references to it on http://www.groovy-lang.org/documentation.html And if you were able to compare the two, which was easier to use, for publishing your documentation both on the web and as a pdf / html page set included in each release? I ask because both services are really very good, and just the sort of thing that we could use! Merlin Beedell [https://www.cryoserver.com/wp-content/uploads/2017/03/ISO-logo-signature.jpg] [https://www.cryoserver.com/wp-content/uploads/2017/03/softech-signature.png] [https://www.cryoserver.com/wp-content/uploads/2017/03/ITE-signature.png] FCS (UK) Limited is registered in England & Wales, Registration Number: 5940018 - Registered Address: Wigglesworth House, 69 Southwark Bridge Road, London SE1 9HH Disclaimer: This e-mail contains proprietary information, some or all of which may be legally privileged and is for the intended recipient only and the information in it are provided in confidence and may not be disclosed to any third party or used for any other purpose without the express permission of FCS (UK) Ltd. If an addressing or transmission error has misdirected this e-mail, please notify the author by replying. If you are not the intended recipient you should not use, disclose, distribute, copy, print or relay on this e-mail. The views expressed in this communication are not necessarily the views held by FCS (UK) Limited.