Hello, I ask you because actually, I’m front of a problem with my code.
Actually, when I install a softwre with my program, it run a Process.run(“crystal”, args: [“file.cr”]).
My problem is, I need to get the status of the runned code inside this file, and not the status of my Process.run.
My code (I just link the relevant part):
if userAgreement
matchingSoftwaresArray.each do |software|
puts ""
file = File.open("ISM.task", "w")
file << "require \"./#{ISM::Default::Path::SoftwaresDirectory + software.port + "/" + software.name + "/" + software.version + "/" + software.version + ".cr"}\"\n"
file << "target = Target.new\n"
file << "target.download\n"
file << "target.check\n"
file << "target.extract\n"
file << "target.patch\n"
file << "target.prepare\n"
file << "target.configure\n"
file << "target.build\n"
file << "target.install\n"
file << "target.clean\n"
file.close
Process.run("crystal",args: ["ISM.task"],output: :inherit)
end
end
Or have you got any suggestion to avoid this problem or improve ?
But I think I can’t avoid to use the crystal interpreter, because the required file in the generated file it’s a script containing the recipe to how to make the software
Is it possible for example inside my generated file to force the running file to return an error code when something in it code is wrong ?
Can you clarify this, please? Do you want your ISM.task
file to return a status code, which you’d then get from your Process.run
, or is it something else you want?
Try this:
if userAgreement
matchingSoftwaresArray.each do |software|
puts ""
file_contents = <<-CODE
require "./#{ISM::Default::Path::SoftwaresDirectory + software.port + "/" + software.name + "/" + software.version + "/" + software.version + ".cr"}"
target = Target.new
target.download
target.check
target.extract
target.patch
target.prepare
target.configure
target.build
target.install
target.clean
exit 1 if <some condition>
CODE
File.write("ISM.task", file_contents)
return_code = Process.run("crystal run",args: ["ISM.task"], output: :inherit)
end
end
Here’s what’s going on:
- I’m using a heredoc string (see string literal docs) to simplify your file writing into simply creating the file contents and then writing it to a file.
- Inside the Crystal file you’re writing, I add that you exit with return code 1 if some condition is fulfilled. It’s not clear to me when you’d want to return a non-zero error code from the particular code you shared, so I just put a space for you to fill in.
-
Process.run
returns the return code of the process, so we assign a variable to that value.
A couple other notes:
- I used
crystal run
rather than just crystal
because it makes it more clear what you’re trying to do.
- In the future, I recommend using the
File.open
method that takes a block instead of creating a new file. That way you don’t have to worry about closing the file manually. While I prefer the heredoc approach in this particular case, your previous file writing code would look like this if you used the block method:
File.open("ISM.task", "w") do |file|
file << "require \"./#{ISM::Default::Path::SoftwaresDirectory + software.port + "/" + software.name + "/" + software.version + "/" + software.version + ".cr"}\"\n"
file << "target = Target.new\n"
file << "target.download\n"
file << "target.check\n"
file << "target.extract\n"
file << "target.patch\n"
file << "target.prepare\n"
file << "target.configure\n"
file << "target.build\n"
file << "target.install\n"
file << "target.clean\n"
end
Hey, thanks you very much, you gave me a lot of usefull things in this reply !
I will come back to you if I need more help, I will try that. Thanks you
1 Like
Just one question as well, is it normal when I call target.download in this generated file, I don’t have the output of wget when it download a file ?
I call wget like this:
Process.run("wget", args: [@information.downloadLinks[0]],
output: :inherit,
chdir: Ism.settings.sourcesPath+"/"+@information.versionName)
wget
outputs to stderr
. See this StackOverflow question for an explanation of why. You can handle this easily by inheriting the error stream as well:
Process.run("wget", args: [@information.downloadLinks[0]],
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath+"/"+@information.versionName)
One question, but you solved almost all of my problem.
Now I just need for this block:
file_contents = <<-CODE
require "./#{ISM::Default::Path::SoftwaresDirectory + software.port + "/" + software.name + "/" + software.version + "/" + software.version + ".cr"}"
target = Target.new
target.download
target.check
target.extract
target.patch
target.prepare
target.configure
target.build
target.install
target.clean
exit 1 if <some condition>
CODE
I need to exit 1 when all of target.something failed. Because actually my file execute all commands without checking if one of them failed.
This seems like a good use case for exceptions. You could raise exceptions with appropriate messages in fail cases for each target#something
and then do something like
file_contents = <<-CODE
require "./#{ISM::Default::Path::SoftwaresDirectory + software.port + "/" + software.name + "/" + software.version + "/" + software.version + ".cr"}"
target = Target.new
begin
target.download
target.check
target.extract
target.patch
target.prepare
target.configure
target.build
target.install
target.clean
rescue ex
STDERR.puts "Error: #{ex.message}"
exit 1 if <some condition>
end
CODE
Hey thanks you !
Now I have one last problem.
My target class inherit of this class:
module ISM
class Software
property information : ISM::SoftwareInformation
property mainSourceDirectoryName : String
def initialize(informationPath : String)
@information = ISM::SoftwareInformation.new
@information.loadInformationFile(informationPath)
@mainSourceDirectoryName = String.new
end
def download
Dir.mkdir(Ism.settings.sourcesPath+"/"+@information.versionName)
Ism.notifyOfDownload(@information)
end
def downloadSource(link : String)
if !Process.run("wget", args: [link],
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath+"/"+@information.versionName).success?
Ism.notifyOfDownloadError(link)
exit 1
end
end
def check
Ism.notifyOfCheck(@information)
end
def extract
Ism.notifyOfExtract(@information)
end
def extractSource(archive : String)
if !Process.run("tar", args: ["-xf", archive],
chdir: Ism.settings.sourcesPath+"/"+@information.versionName).success?
Ism.notifyOfExtractError(archive)
exit 1
end
end
def patch
Ism.notifyOfPatch(@information)
end
def applyPatch(patch : String)
if !Process.run("patch", args: ["-Np1","-i",patch],
chdir: Ism.settings.sourcesPath+"/"+@information.versionName+"/"+@mainSourceDirectoryName).success?
Ism.notifyOfApplyPatchError(patch)
exit 1
end
end
def prepare
Ism.notifyOfPrepare(@information)
end
def moveFile(path : String, newPath : String)
FileUtils.mv( Ism.settings.sourcesPath + "/" +
@information.versionName + "/" +
path,
Ism.settings.sourcesPath + "/" +
@information.versionName + "/" +
newPath)
end
def makeDirectory(directory : String)
Dir.mkdir( Ism.settings.sourcesPath + "/" +
@information.versionName + "/" +
directory)
end
def configure
Ism.notifyOfConfigure(@information)
end
def configureSource(arguments : Array(String), path = String.new)
if !Process.run("./configure", args: arguments,
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath + "/" +
@information.versionName + "/" +
@mainSourceDirectoryName + "/" +
path)
Ism.notifyOfConfigureError(path)
exit 1
end
end
def build
Ism.notifyOfBuild(@information)
end
def makeSource(arguments : Array(String), path = String.new)
if !Process.run("make", args: arguments,
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath + "/" +
@information.versionName + "/" +
@mainSourceDirectoryName + "/" +
path)
Ism.notifyOfMakeError(path)
exit 1
end
end
def install
Ism.notifyOfInstall(@information)
end
def clean
Ism.notifyOfClean(@information)
FileUtils.rm_r(Ism.settings.sourcesPath+"/"+@information.versionName)
end
def uninstall
Ism.notifyOfUninstall(@information)
end
def option?(optionName : String) : Bool
result = false
@information.options.each do |option|
if optionName == option.name
result = option.active
end
end
return result
end
end
end
But when I have an error, and just when I have an error, target.something don’t show my error message, why ?
I added some missing .success? tests, but this didn’t solved the problem
I solved my problem, it’s because I need to avoid :
if !Process.run("wget", args: [link],
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath+"/"+@information.versionName).success?
Ism.notifyOfDownloadError(link)
exit 1
end
and replace to this:
process = Process.run("wget", args: [link],
output: :inherit,
error: :inherit,
chdir: Ism.settings.sourcesPath+"/"+@information.versionName)
if !process.success?
Ism.notifyOfDownloadError(link)
exit 1
end
1 Like