Jenkins runs imported python script before main python script - python

I have a main build script which every jenkins job executes. This main script gets the job name(from Jenkins) and then executes the relevant script for that job name. Right now, I'm using subprocess.check_output to call the relevant script. I was thinking that instead of this, I should just import the script and then call the functions inside. I import it like this:
sys.path.insert(0,os.path.abspath(importLocation))
print("path", sys.path, os.path.abspath(importLocation))
import build
I also tried insert(-1,...) to put it at the end.The way I use it is that I have a couple of print statements in the main script before executing functions in this one.
print("Starting script...")
build.run()
This works fine on the console as it displays "Starting script" before running it. Unfortunately in Jenkins, it always shows build.run()'s output in the console before displaying anything from the main script. I even tried putting build.run() at the very bottom, in an if-statement etc.
Any ideas on how to make it run/show up in Jenkins in the right order?

The child process flushes its output buffers on exit but the prints from the parent are still in the parent's buffer. The solution is to flush the parent buffers before running the child:
print("Starting script...")
sys.stdout.flush()
build.run()

Related

Kill program run with exec(open(file).read()) in python

In my code I am calling a pipeline from a tkinter gui. When the user presses the Run button the entire pipeline starts running. If certain settings are selected a toplevel of the main GUI is called which asks for an aditional file. This all works except when the cancel button or the close window X is pressed. The toplevel closes but the program keeps running. Eventually it will crash because the file is absent. calling sys.exit() isn't the solution because then the entire gui shuts down and I only want the specific toplevel to close and to stop the running file.
How do I kill a file running with exec(open(file).read()) without killing the entire program?
Honestly, you probably shouldn't use exec at all, but assuming you do, exec is still running in the same process and thread as your main program, there's no exiting it without killing the main program.
You should open it in another process, subprocess or thread. Since your exec seem to be running python code, you could simply use:
from subprocess import Popen
p = Popen(['python', filename'])
And then it runs in the background, your normal process continues, and you can kill it at any point with .
p.kill()
It gets more complicated than that if you want to give that process input or read out its output, but that's a matter for a different question. You can start here to see how to read the output: Store output of subprocess.Popen call in a string
A small example to get the output would be something like this:
from subprocess import Popen, PIPE
p = Popen(['python', filename], stdout=PIPE, stderr=PIPE)
output, errors = p.communicate()
However this will wait until the process completes its run, so maybe start all that from another thread, or find another way to get the output (perhaps to a log file)
Notice I used just 'python' in Popen, if the python executable is not in your path or has a different name, you should replace that with the full path to the executable

Is there a way I can store the output of a terminal command into a file using python?

I want to store the output of the terminal command top into a file, using Python.
In the terminal, when I type top and hit enter, I get an output that is real time, so it keeps updating. I want to store this into a file for a fixed duration and then stop writing.
file=open("data.txt","w")
file.flush()
import os,time
os.system("top>>data.txt -n 1")
time.sleep(5)
exit()
file.close()
I have tried to use time.sleep() and then exit(), but it doesn't work, and the only way top can be stopped is in the terminal, by Control + C
The process keeps running and the data is continuously written onto the file, which is not ideal, as one would guess
For clarity: I know how to write the output on to the file, I just want to stop writing after a period
system will wait for the end of the child process. If you do not want that, the Pythonic way is to directly use the subprocess module:
import subprocess
timeout=60 # let top run for one minute
file=open("data.txt","w")
top = subprocess.Popen(["top", "-n", 1], stdout=file)
if top.wait(timeout) is None: # wait at most timeout seconds
top.terminate() # and terminate child
The panonoic way (which is highly recommended for robust code) would be to use the full path of top. I have not here, because it may depend on the actual system...
The issue you could be facing is that os.system starts the process as part of the current process. So the rest of your script will not be run until the command you run has completed execution.
I think what you want to be doing is executing your console command on another thread so that the thread running your python script can continue while the command runs in the background. See run a python program on a new thread for more info.
I'd suggest something like (this is untested):
import os
import time
import multiprocessing
myThread = multiprocessing.process(target=os.system, args=("top>>data.txt -n 1",))
myThread.start()
time.sleep(5)
myThread.terminate()
That being said, you may need to consider the thread safety of os.system(), if it is not thread safe you'll need to find an alternative that is.
Something else worth noting (and that I know little about) is that it may not be ideal to terminate threads in this way, see some of the answers here: Is there any way to kill a Thread?

How to immediately kill Python script after running subprocess?

I made a script which plays a video file by using subprocess.run().
import subprocess
DATA_DIR = 'path\\to\\video\\files'
MEDIA_PLAYER = 'path\\to\\my\\media-player'
# returns path of random video file
p = chooseOne(DATA_DIR)
print('playing {}'.format(p))
# runs chosen path
subprocess.run([MEDIA_PLAYER, p])
But I would like to kill the python script running this code immediately after opening the child subprocess.
Is this possible? And if not, is there an alternative means of opening an external process using Python which would allow the script to terminate?
Note: I am using Python v3.6
Don't use subprocess.run; use os.execl instead. That makes your media player replace your Python code in the current process, rather that starting a new process.
os.execl(MEDIA_PLAYER, p)
subprocess.run effectively does the same thing, but forks first so that there are temporarily two processes running your Python script; in one, subprocess.run returns without doing anything else to allow your script to continue. In the other, it immediately uses one of the os.exec* functions—there are 8 different varieties—to execute your media player. In your case, you just want the first process to exit anyway, so save the effort of forking and just use os.execl right away.

How can I check whether the script started with cron job is completed?

I start a script and I want to start second one immediately after the first one is completed successfully?
The problem here is that this script can take 10min or 10hours according to specific cases and I do not want to fix the start of the second script.
Also, I am using python to develop the script, so if you can provide me a solution with python control on the cron it will be OK.
Thank you,
You can use a lock file to indicate that the first script is still running.
You could use atexit module. As part of first script, you could register the function. From the registered function at exit, you could call the second script or execute the second script using system.
import atexit
def at_exit():
print 'invoke the second script'
atexit.register(at_exit)

Run a shell script in background

I have a shell script which I am calling in Python using os.system("./name_of_script")
I would prefer to do this call based on user input(ie a user types "start" and the call is done, and some other stuff in the python program is also done, when a user types "stop" the script is terminated) but i find that this call takes up the whole focus on the terminal (I dont really know the right word for it, but basically the whole program stalls on this call since my shell script executes until a keyboard interrupt is received). Then when I do a keyboard interrupt, that is the only moment that the shell script stops executing and the rest of the code afterwards is executed. Is this possible in python?
Simply constructing a Popen object, as in:
p = subprocess.Popen(['./name_of_script'])
...starts the named program without blocking on it to complete.
If you later want to see if it's done yet, you can check p.poll() for an update on its status.
This is also faster and safer than os.system(), in that it doesn't involve a shell (unless the script you're invoking runs one itself), so you aren't exposing yourself to shellshock, shell injection vulnerabilities, or other shell-related issues unnecessarily.

Categories

Resources