Run Tortoise SVN command line commands with a hidden window - ruby

I have Tortoise SVN with a command-line interface installed. The installation path is C:\Program Files\TortoiseSVN\bin where svn.exe is used whenever I use any SVN command.
I developed a Ruby Windows application which is run as a background process. This application runs the command like
svn info "#{path_to_repository}"
This command invokes svn.exe as I mentioned.
The problem is, svn.exe flashes a command prompt for a second and terminates, thus if I run svn info ten times for ten different repositories then the screen flickers ten times as this command is developed to run in a timely fashion, the screen flickers ten times regularly.
What I need is a way to run SVN commands through Tortoise SVN without the svn.exe popping up the screen and closing.

Ruby has numerous way of executing command in shell, however, with all the options a command line popup seem to appear when using in GUI App.
Depending on what details you are looking for in svn info, one option you can use something like WebSVN and see if you can want to scrape the GUI or get data from its RSS feed. Take a look at demo site of this product.
If you have very specific and minimal needs, then, you can also choose to build a small REST API which can query the subversion server using command line. You can in that case call that REST API to fetch the data and avoid popping up of command windows.
If you are really short on time or do not have server infrastructure to host REST API, then, you can think of creating a Ruby App that runs a socket server and can run the shell command on receiving commands from client. Then, you can make your GUI App connect to the socket server using socket client and ask the server app to execute svn info and return result. Go through the tutorial on building such interacting apps. You can then choose to run them side-by-side on same PC.
Another alternative is to use Ruby SVN bindings. It may require some digging around to get this to work.
Here is quick starter code:
server.rb - a ruby TCP server that accepts commands and executes them in shell
require 'socket'
server = TCPServer.open(2000) # Socket to listen on port 2000
puts "Listening now #{server.addr}"
loop {
Thread.start(server.accept) do |client|
cmd = client.gets
puts "Processing #{cmd} from #{client.peeraddr}"
IO.popen(cmd) { |s| result = [];
while (line = s.gets) do
client.puts line.chop
end;
}
client.close
end
}
app.rb A Shoes GUI app that issues svn info command to TCP server being run by server.rb
require 'socket'
Shoes.app {
stack do
#push = button "Get SVN Info"
#note = para ""
end
#push.click {
hostname = 'localhost'
port = 2000
result = []
s = TCPSocket.open(hostname, port)
s.puts "svn info trunk/backend"
while line = s.gets
result << line.chop
end
s.close
#note.replace result.join("\n")
}
}
app.rb should be launched using shoes app.rb command.

This behavior is not specific to Ruby but to the Windows command-line interpreter. There are several ways to work around it.
Try running the svn command prefixed by cmd.exe /C which should not flash the command prompt window. A variation of that is to use start /min as a prefix instead. This doesn't work under all circumstances and I don't have a Ruby on Windows handy to check.
Create a .vbs wrapper for your command. Since .vbs is not handled by the command-line interpreter, its window will not be created. See "How to run a batch file without launching a 'command window'?" for details.
The best option is to use a WinAPI wrapper gem to get access to ShellExecute function which is pretty flexible:
require 'win32ole'
# Create an instance of the Windows Shell object...
shell = WIN32OLE.new('Shell.Application')
# The shell object's ShellExecute method performs a specified operation on a specified file. The syntax is...
shell.ShellExecute(FILE, ARGUMENTS, DIRECTORY, OPERATION, SHOW)
This example is taken from "Launching Apps and Printing Docs with the Windows Shell" where you can find more details.
For your purpose it would be something like
shell.ShellExecute('svn.exe', 'info', path_to_repository, 'open', 0)
Learn more about ShellExecute usage.

Related

Python Not Running Shell Commands After Reboot Using Launch Agent

So, I'm starting a Python (2.7) script via a launch agent, on macOS 10.13. The script runs, and during execution, it triggers a restart of the computer. When the computer turns back on and logs in, the launch agent runs the script again. The script reads the logs, and does a switch:case to pick up where it left off.
The problem is, after the restart, the python script is unable to execute some shell commands. ls -l works fine. However, when I try to run something that isn't in /bin, it seems to just... skip over it. No errors, it simply doesn't do it.
Here's the related code. I've removed most of the specifics, as well as the switch control, because I've verified they are working, independently.
#!/usr/bin/python
import logging
import os
import subprocess
import time
#globals
path_to_plist = 'User/Me/Library/Preferences/PathTo.plist'
def spot_check():
#determine where we are in the test, verified it works
return loop_number
def func_that_checks_stuff():
results = subprocess.check_output(['System/Library/Path/To/tool','-toolarg'])
###process results
logging.info(results)
def restarts(power_on, power off):
#sets plist key values for the restart app
subprocess.Popen('defaults write {} plist_key1 {}'.format(path_to_plist, power_on), shell=True
subprocess.Popen('defaults write {} plist_key2 {}'.format(path_to_plist, power_off), shell=True
#run the restart app, which is a GUI application in /Applications
logging.info('Starting restart app')
subprocess.Popen('open -a RestartApp.app', shell=True)
time.sleep(power_on + 5)
def main():
###setup and config stuff, verified its working
#switch control stuff, verified its working
loop = spot_check()
if loop == 0:
#tool that shows text on the screen
subprocess.Popen('User/Me/Library/Scripts/Path/To/Text/tool -a -args', shell=True)
logging.info('I just ran that tool')
subprocess.check_output('ls -l', shell=True)
restarts(10, 0)
if loop == 1:
func_that_checks_stuff()
subprocess.Popen('User/Me/Library/Scripts/Path/To/Text/tool -a args', shell=True)
logging.info('Hey I ran that tool again, see?')
restarts(10, 0)
else:
func_that_checks_stuff()
subprocess.Popen('User/Me/Library/Scripts/Path/To/Text/tool -a args', shell=True)
print 'You finished!'
if __name__ == '__main__':
main()
So, if I start this using my launch agent, it will run through every sequence just fine.
On the first loop (prior to the restart), EVERYTHING works. All logging, all tools, everything.
After the restart, all the logging works, so I know it's following the switch control. The func_that_checks_stuff() works, and logs it's output correctly. The ls -l' call shows me exactly what I should see. But,Path/To/Text/tooldoesn't run, and when I callrestarts()`, it never opens the app.
No errors are produced, at least that I can find
What am I doing wrong? Is it something to do with the tool paths?
Update:
As it turns out, the solution was to add a ~20 second delay at the start of the script. It seems like it was trying to run the commands in question before Window Server had finished loading, and that freaked everything out. Not a particularly elegant solution, but it works for what I need in this project.

Start and Kill the browser using Ruby

All,
I've got a problem which I need your help.
Using Ruby 1.9.3 in Windows, I'm starting a browser with the following command:
system('start http://www.stackoverflow.com')
I've tried getting the pid of the above system cmd in various ways like exec, Thread and IO.popen. But everytime I get the different PID which I assume the PID of the ruby process.
But I need the PID of the started browser, so that I can kill the browser once I finish my task at the end.
Note that I don't want to use Watir / Selenium or any automation tool.
Kindly help me on this.
Don't use start, it will spawn new window, open browser and then detach the window. Specify the browser path explicitly to solve the problem:
browser = %q{"C:\Program Files\Internet Explorer\iexplore.exe"}
pipe = IO.popen("#{browser} http://www.stackoverflow.com")
puts pipe.pid
Process.kill(9, pipe.pid)
Run start /? for help message of start command.

Remote SSH command execution hangs in ruby using Net::SSH for a particular command

I am trying to connect the remote ssh server via ruby using
Net::SSH.It is working fine for me for all the commands provided via
script and i could able to read the output of the command
successfully. But when i use the below command it is getting stuck in
SSH.exec!(cmd) and control is not returned from the line. Only if i
click Ctrl+c in command line the script is getting ended. The command
is ./wcsadmin.sh start --> this is used to start the processes of my
application in remote server
Please find the below code snippet of my ruby script:
Net::SSH.start(host, username, :password => password) do |ssh|
puts 'before exit'
output = ssh.exec!(/opt/wcsadmin.sh start)
puts 'Executed command'
The output of the command when i do it manually is :
[root#test bin]# ./wcsadmin.sh start
Starting Network Control System...
This may take a few minutes... stty: standard input: Invalid argument
Network Control System started successfully.
Starting SAM daemon... Done. Starting DA daemon... Starting DA syslog
daemon... start
if i use ssh.exec('./wcsadmin.sh start') the only difference is the
above output is getting printed but still the program is never ended.I
need to manually end it by hitting ctrl+c. When i searched in google i
could find you can use
nohup command('nohup /opt/wcsadmin.sh start >/tmp/teststartserver.log 2>&1')
to skip the hangup signals and tried the same.This also writes the output to teststartserver.log but
getting hanged.Can anyone please help me out on this issue?
Thanks in Advance!
Thanks, Meena
If the command itself doesn't return right away, then SSH.exec! will block further execution until the command returns. If for some reason you lose remote contact, then SSH.exec! may not know that you have lost connectivity and it will continue to block.
You could try putting the command in the background:
output = ssh.exec!('/opt/wcsadmin.sh start &')
Or maybe look at the documentation on that command and maybe it has some sort of --no-wait option that will allow it to return immediately, even if it is still working.

Manage a Thin server through a Ruby script

I have a project where I have a sinatra app and I want to launch it with thin through a admin ruby script file. I want to be able to start, stop and restart it, also being able to daemonize it if asked to. This is, I want to have something like this in my script:
bin/myscript
require 'MyCLI'
MyCLI.new(ARGV).run
lib/mycli.rb
class MyCLI
# instantiate and other methods (inspired by thin runner)
...
def run
# parse commands and options
...
# then process command
case #command
when 'start'
#server = Thin::Server.new(host, port, MyModule::MyAppClass)
#server.start
when 'stop'
# ?
when 'restart'
# ?
else
raise "Unknown command"
end
end
end
But I'm struggling with some problems,
I need to daemonize it or not, depending on some command option and cant find if this is possible to do passing some parameter to #new after reading docs and digging in some of the code.
Stopping would be as easy as #server.stop, but as my script instantiates a mycli object at each command line request, I do not have a single object so #server vanishes after the start request, so I think that the only solution would be to control the PID (right??), but cant find how thin manages that. Also, running it in foreground would not work with this pid approach I presume.
What would be the proper way to restart it?
Has anyone a best solution for this?
I end up using Rack::Server.start(app, host, port, env, daemonize(Y/N), pid_file).
It works great, and it will pick up the thin handler if available.

Can a standalone ruby script (windows and mac) reload and restart itself?

I have a master-workers architecture where the number of workers is growing on a weekly basis. I can no longer be expected to ssh or remote console into each machine to kill the worker, do a source control sync, and restart. I would like to be able to have the master place a message out on the network that tells each machine to sync and restart.
That's where I hit a roadblock. If I were using any sane platform, I could just do:
exec('ruby', __FILE__)
...and be done. However, I did the following test:
p Process.pid
sleep 1
exec('ruby', __FILE__)
...and on Windows, I get one ruby instance for each call to exec. None of them die until I hit ^C on the window in question. On every platform I tried this on, it is executing the new version of the file each time, which I have verified this by making simple edits to the test script while the test marched along.
The reason I'm printing the pid is to double-check the behavior I'm seeing. On windows, I am getting a different pid with each execution - which I would expect, considering that I am seeing a new process in the task manager for each run. The mac is behaving correctly: the pid is the same for every system call and I have verified with dtrace that each run is trigging a call to the execve syscall.
So, in short, is there a way to get a windows ruby script to restart its execution so it will be running any code - including itself - that has changed during its execution? Please note that this is not a rails application, though it does use activerecord.
After trying a number of solutions (including the one submitted by Byron Whitlock, which ultimately put me onto the path to a satisfactory end) I settled upon:
IO.popen("start cmd /C ruby.exe #{$0} #{ARGV.join(' ')}")
sleep 5
I found that if I didn't sleep at all after the popen, and just exited, the spawn would frequently (>50% of the time) fail. This is not cross-platform obviously, so in order to have the same behavior on the mac:
IO.popen("xterm -e \"ruby blah blah blah\"&")
The classic way to restart a program is to write another one that does it for you. so you spawn a process to restart.exe <args>, then die or exit; restart.exe waits until the calling script is no longer running, then starts the script again.

Resources