Write to file via jenkins post-groovy script on slave - groovy

I'd like to do something very simple: Create/write to a file located in the remote workspace of a slave via the jenkins groovy post-build script plug-in
def props_file = new File(manager.build.workspace.getRemote() + "/temp/module.properties")
def build_num = manager.build.buildVariables.get("MODULE_BUILD_NUMBER").toInteger()
def build_props = new Properties()
build_props["build.number"] = build_num
props_file.withOutputStream { p ->
build_props.store(p, null)
}
The last line fails, as the file doesn't exist. I'm thinking it has something to do with the output stream pointing to the master executor, rather than the remote workspace, but I'm not sure:
Groovy script failed:
java.io.FileNotFoundException: /views/build_view/temp/module.properties (No such file or directory)
Am I not writing to the file correctly?

While writing onto slave you need to check the channel first and then you can successfully create a file handle and start reading or writing to that file:
if(manager.build.workspace.isRemote())
{
channel = manager.build.workspace.channel;
}
fp = new hudson.FilePath(channel, manager.build.workspace.toString() + "\\test.properties")
if(fp != null)
{
String str = "test";
fp.write(str, null); //writing to file
versionString = fp.readToString(); //reading from file
}
hope this helps!

Search for words The post build plugin runs on the manager and doing it as you say will fail if you are working with slaves! on the plugin page (the link to which you've provided) and see if the workaround there helps.

Does the folder /views/build_view/temp exist?
If not, you will need to do new File( "${manager.build.workspace.remote}/temp" ).mkdirs()

Related

Groovy code to read rabbitMQ working on Windows, not working on Linux

Need: Read from rabbitMQ with AMQPS
Problem: ConsumeAMQP is not working so I'm using groovy script that's working on windows and not working on linux. Error message is:
groovy.lang.MissingMethodException: No signature of method: com.rabbitmq.client.ConnectionFactory.setUri() is applicable for argument types: (String) values: [amqps://user:xxxxxxxXXXxxxx#c-s565c7-ag77-etc-etc-etc.mq.us-east-1.amazonaws.com:5671/virtualhost]
Possible solutions: getAt(java.lang.String), every(), every(groovy.lang.Closure)
Troubleshooting:
Developed code on python to test from my machine using pika lib and it's working with URL amqps. It reads from rabbitMQ. no connection issues.
put the python code on the nifi server (1.15.3) machine, installed python and pika lib, execute on the command line, it's working on the server and reads from rabbitMQ.
Develop groovy code to test from my windows apache nifi (1.15.3)` and it's working, it's reading from rabbitMQ client system.
Copy the code (copy past) to the nifi server, uploaded the .jar lib also. Not working with this error message. create a groovy file and execute the code. not working.
Can anyone help me?
NOTE: I want to use groovy code to output the results to the flowfile.
#Grab('com.rabbitmq:amqp-client:5.14.2')
import com.rabbitmq.client.*
import org.apache.commons.io.IOUtils
import java.nio.charset.*
// -- Define connection
def ConnectionFactory factory = new ConnectionFactory();
factory.setUri('amqps://user:password#a-r5t60-etc-etc-etc.mq.us-east-1.amazonaws.com:5671/virtualhost');
factory.useSslProtocol();
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// -- Waiting for messages.");
boolean noAck = false;
int count = 0;
while(count<10) {
GetResponse response = channel.basicGet("db-user-q" , noAck)
if (response != null) {
byte[] body = response.getBody()
long deliveryTag = response.getEnvelope().getDeliveryTag()
def msg = new String(body, "UTF-8")
channel.basicAck(response.envelope.deliveryTag, false)
def flowFile = session.create()
flowFile = session.putAttribute(flowFile, 'myAttr', msg)
session.transfer(flowFile, REL_SUCCESS);
}
count++;
}
channel.close();
connection.close();
The following code is suspect:
def ConnectionFactory factory = new ConnectionFactory();
You don't need both def and a type ConnectionFactory. Just change it to this:
ConnectionFactory factory = new ConnectionFactory()
You don't need the semi-colon either. The keyword def is used for dynamic typing situations (or laziness), and specifying the type (ie ConnectionFactory) is for static typing situations. You can't have both. It's either dynamic or static typing. I suspect Groovy VM is confused by what type the object is hence why it can't figure out if setUri exists or not.

Check if file exists using bash inside Java program?

So I am witting a java program for interacting with filesystem.
Java program itself cannot run as super user. I created a special user for this program and gave it some special privileges to run some commands without password (via visudo file).
So I I'd like to check if a file exist. I used:
if(f.exists() && !f.isDirectory()) but the problem is this fails if I am checking if files exist that is read/write protected or if it belongs to another user.
That is why I need to use bash. for example, when I am retrieving information about file I use the following:
String[] command = new String[] { "sudo", "stat", filepath, "-c", "%F##%s##%U##%G##%X##%Y##%Z" };
process = runtime.exec(command); and then just parse the output.
For example moving a file I use this:
String[] command = new String[] {
"sudo",
"-u",
user,
"mv",
source,
target
};
So now I am looking for a way to get simple true/false response when checking if file exist.
I think I could use find command or something similar?
I've solved my issue by using the following command:
String[] command = new String[] { "sudo", "-u", user, "test", "-f", path };
Where user is user who I am running command as. And path is the path-to-file we are testing.
I then read the execute and read command's output in the code below.
I hope it helps someone someday...
process = runtime.exec(command);
errbr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((messageLine = errbr.readLine()) != null) {
message += messageLine + ";";
}
br = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((messageLine = br.readLine()) != null) {
message += messageLine;
}

Gradle: How to upload release APK file over FTP after build

I want to upload automatically the APK file to the server when building the release version.
To do so, I'm going to use FTP protocol.
I'm new regarding Gradle scripting. I used those 2 questions (this and this) as a base but something is not working out.
Could anyone point out what it is?
This is the code (on build.gradle):
gradle.buildFinished {
println("---- Build finished. This message appears ----")
task ftp << {
project.logger.lifecycle('-- This message does not appear --')
ant {
taskdef(name: 'ftp',
classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
classpath: configurations.ftpAntTask.asPath)
def destination = "ftp://xxxxxxxxxx#xxx.surftown.com/xxxxx/"
def source = null
android.applicationVariants.all { variant ->
if ( (variant.name).equals("release") ) {
variant.outputs.each { output ->
source = output.outputFile
}
}
}
def user = 'xxxxxxxxx'
def pass = 'xxxxxxxxx'
ftp(server: source, userid: user, password: pass, remoteDir: destination)
}
}
gradle.buildFinished registers a hook executed at the end of the build. In your case it just creates the ftp task.
Use this if the build task is involved :
build.finalizedBy(ftp)
Otherwise, to make sure it works whatever the invoked task :
tasks.all*.finalizedBy(ftp)
By the way, it was explained in the comment section of first answer of your first link.

File server to SharePoint Online: folder to document library structure diff tool?

Do you know if there is any kind of tool (it would be cool if it is for free) that compares the file structure of a folder in a File Server to a SharePoint Online Document Library and tells you the difference?
The point is we are getting hands on a partially migrated File Server to SharePoint Online and the migration status of some folders is unknown to us. We already have a 3rd party migration tool to finish the migration but we need to know what is still pending to be uploaded. Any idea?
Thanks in advance.
We use sharegate for our migration. In your situation I might just run migrations on small sections with it set to "skip existing". That doesn't directly answer your question though.
In your case I would map both the File server and the SharePoint online instance as drives on a computer (using WebDAV) and hack together an app in your favorite language to compare the two directory structures.
Here is a java program that does that:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
public class Launcher {
static PrintWriter fileOut;
public static void main(String[] args) throws IOException {
File fileStore = new File("N:\\"); //filestore dir top level
File sp = new File("M:\\");//sp directory top level (mapped)
File out = new File("C:\\Temp\\results.txt");
fileOut = new PrintWriter(out);
recurse(fileStore, sp);
fileOut.close();
}
private static void recurse(File dir1, File dir2)
{
File [] dirFiles;
if(dir2 == null)
dirFiles = new File[0];
else
dirFiles=dir2.listFiles();
File match;
for(File f1 : dir1.listFiles())
{
System.out.println(f1.getAbsolutePath());
match=null;
for(File f2:dirFiles)
if(f1.getName().equalsIgnoreCase(f2.getName()))
match=f2;
if(f1.isDirectory() && f1.canRead())
try{
recurse(f1,match);
}
catch(Exception e){}
else if (match == null)
fileOut.write(f1.getAbsolutePath()+"\r\n");
}
}
}
It writes to the given text file each file that is not in the 2nd directory structure.
You could run this code in an IDE like eclipse.

C# Process.Start is messing with URI's inside a batch file

This is just a quick question that I am sure someone will be able to answer quickly as I am most likely just missing something.
Lets say I have the following directory layout
Folder1
-> CurrentlyRunning.EXE
-> Folder2
ProcessToStart.Bat
ApplicationToStartFromBat.exe
This is the code inside the applications.
CurrentlyRunning.EXE:
var proc = new Process
{
StartInfo =
{
FileName = "Folder2/ProcessToStart.Bat",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
}
};
proc.Start();
ProcessToStart.Bat:
START ApplicationToStartFromBat.exe
Now, if I run ProcessToStart.Bat by double clicking on it, it will open ApplicationToStartFromBat.exe with no problems (which is good). If I run CurrentlyRunning.EXE (which will execute the code I posted above) the BAT file fails saying it can't find my EXE (which is really weird).
If I change the BAT file to:
START Folder2/ApplicationToStartFromBat.exe
and then run CurrentlyRunning.EXE, the bat will then properly open ApplicationToStartFromBat.exe. My problem is I can not change the code inside the bat for one reason or another.
Why is proc.Start() causing the bat file search root directory to change, and how do I stop this from happening?
Thanks
I think it is to do with where the working directory is for your exe file.
Try using ProcessStartInfo.WorkingDirectory to set the correct directory for your batch file.
var proc = new Process
{
StartInfo =
{
FileName = "Folder2/ProcessToStart.Bat",
WorkingDirectory = "DirectoryPath";
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
}
};
proc.Start();

Resources