I want to create a macro for which a directory path will be given. The macro in-turn has to run another macro for all the files in the directory. Is that possible in gdb ?
I assume that the macro you want to run is a gdb macro. To solve this, I suggest you use the Python support in gdb to encompass this. Put the following in forallindir.py
import gdb
import os
class ForAllInDir (gdb.Command):
"Executes a gdb-macro for all files in a directory."
def __init__ (self):
super (ForAllInDir, self).__init__ ("forallindir",
gdb.COMMAND_SUPPORT,
gdb.COMPLETE_NONE, True)
def invoke(self, arg, from_tty):
arg_list = gdb.string_to_argv(arg)
path = arg_list[0]
macro = arg_list[1]
for filename in os.listdir(path):
gdb.execute(macro + ' ' + os.path.join(path, filename))
ForAllInDir()
Then in gdb to source forallindir.py and it should work. For example, define a test macro like
define testit
print "i got called with $arg0"
end
and forallindir /tmp/xx testit with two sample files in that directory will give us
$1 = "i got called with /tmp/xx/ape"
$2 = "i got called with /tmp/xx/bear"
Hope that helps.
Related
I'm trying to add a simple line in fstab within
the final rootfs that Yocto builds.
My first approach was to add my own fstab in my layer meta-mylayer/recipes-core/base-files/base-files/fstab and the proper meta-mylayer/recipes-core/base-files/base-files/base-files_%.bbappend which only have the following line:
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
And it works, but as the title of my question says, i want to modify fstab based on the recipe-image i want to build i.e. dev-image & prod-image.
After some investigation i think i have 2 options
Modify fstab within the recipe image, extending the do_install task...
dev-image.bb
--------------
DESCRIPTION = "Development Image"
[...]
inherit core-image
do_install_append () {
echo "======= Modifying fstab ========"
cat >> ${D}${sysconfdir}/fstab <<EOF
# The line i want to Add
EOF
}
[...]
--------------
Problem is that i'm actually not seeing my modified line in my final /etc/fstab and bitbake is not showing any build error or warning about this, actually, i'm not even able to see the echo-trace i put.
My second attempt was to handle these modifications with packages and depending on the recipe-image i will be able to add the package for *-dev or *-prod. This idea was taken from Oleksandr Poznyak in this answer in summary he suggest the following:
1) Create *.bbappend recipe base-files_%s.bbappend in your layer. It
appends to poky "base-files" recipe.
2) Create your own "python do_package_prepend" function where you should
make your recipe produce two different packages
3) Add them to DEPENDS in your image recipe
And based on his example i made my own recipe:
base-files_%.bbappend
-------------------------
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
SRC_URI += "file://fstab-dev \
file://fstab-prod \
"
PACKAGES += " ${PN}-dev ${PN}-prod"
CONFFILES_${PN}-dev = "${CONFFILES_${PN}}"
CONFFILES_${PN}-prod = "${CONFFILES_${PN}}"
pkg_preinst_${PN}-dev = "${pkg_preinst_${PN}}"
pkg_preinst_${PN}-prod = "${pkg_preinst_${PN}}"
RREPLACES_${PN}-dev = "${PN}"
RPROVIDES_${PN}-dev = "${PN}"
RCONFLICTS_${PN}-dev = "${PN}"
RREPLACES_${PN}-prod = "${PN}"
RPROVIDES_${PN}-prod = "${PN}"
RCONFLICTS_${PN}-prod = "${PN}"
python populate_packages_prepend() {
import shutil
packages = ("${PN}-dev", "${PN}-prod")
for package in packages:
# copy ${PN} content to packages
shutil.copytree("${PKGD}", "${PKGDEST}/%s" % package, symlinks=True)
# replace fstab
if package == "${PN}-dev":
shutil.copy("${WORKDIR}/fstab-dev", "${PKGDEST}/${PN}-dev/etc/fstab")
else:
shutil.copy("${WORKDIR}/fstab-prod", "${PKGDEST}/${PN}-prod/etc/fstab")
}
-------------------------
And in my recipe-image(dev-image.bb) i added base-files-dev packet
dev-image.bb
--------------
DESCRIPTION = "Development Image"
[...]
inherit core-image
IMAGE_INSTALL = " \
${MY_PACKETS} \
base-files-dev \
"
[...]
--------------
Problem with this, is that i'm not familiarized with phyton indentation so probably i'm messing things up, the error log shows as follows.
DEBUG: Executing python function populate_packages
ERROR: Error executing a python function in exec_python_func() autogenerated:
The stack trace of python calls that resulted in this exception/failure was:
File: 'exec_python_func() autogenerated', lineno: 2, function: <module>
0001:
*** 0002:populate_packages(d)
0003:
File: '/home/build/share/build_2/../sources/poky/meta/classes/package.bbclass', lineno: 1138, function: populate_packages
1134:
1135: workdir = d.getVar('WORKDIR')
1136: outdir = d.getVar('DEPLOY_DIR')
1137: dvar = d.getVar('PKGD')
*** 1138: packages = d.getVar('PACKAGES').split()
1139: pn = d.getVar('PN')
1140:
1141: bb.utils.mkdirhier(outdir)
1142: os.chdir(dvar)
File: '/usr/lib/python3.6/shutil.py', lineno: 315, function: copytree
0311: destination path as arguments. By default, copy2() is used, but any
0312: function that supports the same signature (like copy()) can be used.
0313:
0314: """
*** 0315: names = os.listdir(src)
0316: if ignore is not None:
0317: ignored_names = ignore(src, names)
0318: else:
0319: ignored_names = set()
Exception: FileNotFoundError: [Errno 2] No such file or directory: '${PKGD}'
DEBUG: Python function populate_packages finished
DEBUG: Python function do_package finished
I will really appreciate any clue or sort of direction, i'm not an Yocto expert so maybe the options that i suggest are not the most elegant and probably there is a better way to do it, so be free to give me any recommendation.
Thank you very much.
UPDATE:
As always, i was not the only one trying this, the way that i make it work was thanks this answer the only inconvenience with this is that you need to rm what you want to install through a .bbappend but for now is fine for me.
I also tried to do the same with bbclasses, which for me, it is a more elegant wayto do it, but i failed... i got the following error
ERROR: base-files-dev-3.0.14-r89 do_packagedata: The recipe base-files-dev is trying to install files into a shared area when those files already exist. Those files and their manifest location are:
I tried to rm fstab within the .bbappend but the same error is showed
Maybe somebody will share what i'm doing wrong...
If you don't find this post valuable please remove...
Your recipe which base on Oleksandr doesn't work due to dropped support for variables expansion in newer Poky.
https://www.yoctoproject.org/docs/latest/mega-manual/mega-manual.html#migration-2.1-variable-expansion-in-python-functions
Error explicit says:
Exception: FileNotFoundError: [Errno 2] No such file or directory: '${PKGD}'
It didn't expand the variable.
P.S.
This is not a proper answer to Your question but SO blocks comments.
Silly question, but I want to do some processing on a dataset and put them into different CSVs, like UDID1.csv, UDID2.csv, ..., UDID1000.csv. So this is my code:
for i in 1..1000
logfile = File.new('C:\Users\hp1\Desktop\Datasets\New File\UDID#{i}\.csv',"a")
#I'll do some processing here
end
But the program throws an error when running because of the UDID#{i} part. So, how to overcome this issue? Thanks.
Edit: This is the error:
in `initialize': No such file or directory # rb_sysopen - C:\Users\hp1\Desktop\Datasets\New File\udid#{1}\.csv (Errno::ENOENT)from C:/Ruby21/bin/hashedUDID.rb:38:in `new' from C:/Ruby21/bin/hashedUDID.rb:38:in '<main>'
The ' is one problem, another problem is the path.
In your posting the New File must exist as a directory. Inside this directory must exist another directories like UDID0001. This gets a .csv file.
Correct is (I don't use the non-rubyesk for-loop):
1.upto(1000) do |i|
logfile = File.new("C:\\Users\\hp1\\Desktop\\Datasets\\UDID#{i}.csv", "a")
#I'll do some processing here
logfile.close #Don't forget to close the file
end
Inside " the backslash must be masked (\\). Instead you may use /:
logfile = File.new("C:/Users/hp1/Desktop/Datasets/New File/UDID#{i}/.csv", "a")
Another possibility is the usage of %i to insert the number:
logfile = File.new("C:/Users/hp1/Desktop/Datasets/New File/UDID%02i/.csv" % i, "a")
I prefer to use open, then the file is closed with the end of the block:
File.open("C:/Users/hp1/Desktop/Datasets/New File/UDID%04i/.csv" % i, "a") do |logfile|
#I'll do some processing here
end #closes the file
Warning:
I'm not sure, if you really want to create 1000 log files (The File is opened inside the loop. so each step creates a file.).
If yes, then the %04i-version has the advantage, that the files get all the same number of digits (starting with 0001 and ending with 1000).
(1..10).each { |i| logfile = File.new("/base/path/UDID#{i}.csv") }
You must use double quote (") when you need string interpolation.
#{} can only be used in strings with double quotes ". So change your code to:
for i in 1..1000
logfile = File.new("C:\Users\hp1\Desktop\Datasets\New File\UDID#{i}\.csv","a")
# other stuff
end
I want to save my files in specific path..
I have used like this
file_name = gets
F = open.(Dir.pwd, /data/folder /#{#file_name },w+)
I'm not sure whether the above line is correct or not! Where Dir.pwd tell the directory path followed by my folder path and the file name given.
It should get store the value on the specific path with the specific file name given. Can anyone tell me how to do that.
Your code has multiple errors. Have you ever tried to execute the script?
Your script ends with:
test.rb:7: unknown regexp options - fldr
test.rb:7: syntax error, unexpected end-of-input
F = open.(Dir.pwd, /data/folder /#{#file_name },w+)
First: You need to define the strings with ' or ":
file_name = gets
F = open.(Dir.pwd, "/data/folder/#{#file_name}","w+")
Some other errors:
You use file_name and later #file_name.
The open method belongs to File and needs two parameters.
The file is defined as a constant F. I would use a variable.
The path must be concatenated. I'd use File.join for it.
You don't close the file.
After all these changes you get:
file_name = gets
f = File.open(File.join(Dir.pwd, "/data/folder/#{file_name}"),"w+")
##
f.close
and the error:
test.rb:29:in `initialize': No such file or directory # rb_sysopen - C:/Temp/data/folder/sdssd (Errno::ENOENT)
The folder must exist, so you must create it first.
Now the script looks like:
require 'fileutils'
dirname = "data/folder"
file_name = gets.strip
FileUtils.mkdir_p(dirname) unless Dir.exists?(dirname)
f = File.open(File.join(Dir.pwd, dirname, file_name),"w+")
##fill the content
f.close
I am using the msutter DSC module for puppet. While reading through the source code, I come across code like this (in dsc_configuration_provider.rb):
def create
Puppet.debug "\n" + ps_script_content('set')
output = powershell(ps_script_content('set'))
Puppet.debug output
end
What file defines the powershell function or method? Is it a ruby builtin? A puppet builtin? Inherited from a class? I know that it is being used to send text to powershell as a command and gathering results, but I need to see the source code to understand how to improve its error logging for my purposes, because certain powershell errors are being swallowed and no warnings are being printed to the Puppet log.
These lines in file dsc_provider_helpers.rb may be relevant:
provider.commands :powershell =>
if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
"#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
else
'powershell.exe'
end
Surely this defines where the Powershell executable is located, but gives no indication how it is called and how its return value is derived. Are stdout and stderr combined? Am I given the text output or just the error code? etc.
This is core Puppet logic. When a provider has a command, like
commands :powershell => some binary
That is hooked up as a function powershell(*args).
You can see it with other providers like Chocolatey:
commands :chocolatey => chocolatey_command
def self.chocolatey_command
if Puppet::Util::Platform.windows?
# must determine how to get to params in ruby
#default_location = $chocolatey::params::install_location || ENV['ALLUSERSPROFILE'] + '\chocolatey'
chocopath = ENV['ChocolateyInstall'] ||
('C:\Chocolatey' if File.directory?('C:\Chocolatey')) ||
('C:\ProgramData\chocolatey' if File.directory?('C:\ProgramData\chocolatey')) ||
"#{ENV['ALLUSERSPROFILE']}\chocolatey"
chocopath += '\bin\choco.exe'
else
chocopath = 'choco.exe'
end
chocopath
end
Then other locations can just call chocolatey like a function with args:
chocolatey(*args)
Which is the best way of redirect the output of a command to a VTE terminal?
i came with this idea:
On the VTE execute:
tty > /usr/tmp/terminal_number
then read the file from the python program:
with open('/usr/tmp/terminal_number', 'r') as f:
self.VTE_redirect_path=f.readline()
then execute the bash commands, for exemple:
os.system('''echo "foo" > {0}'''.format(self.VTE_redirect_path))
The problem of this method is that the file terminal_number containing /dev/pts/# needs to be refreshed. Also i don't really like the idea of having to create files to communicate. Is there any direct solution?
#Quentin The solution that you gave me prints the console output really bad (it doesn't indents) so i had to use my solution. Here is a clear example:
from gi.repository import Gtk, GObject, Vte, GLib
import os, time, threading
def command_on_VTE(self,command):
length=len(command)
self.terminal.feed_child(command, length)
class TheWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="inherited cell renderer")
self.set_default_size(600, 300)
self.terminal=Vte.Terminal()
self.terminal.fork_command_full(
Vte.PtyFlags.DEFAULT, #default is fine
os.environ['HOME'], #where to start the command?
["/bin/bash"], #where is the emulator?
[], #it's ok to leave this list empty
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
None, #at least None is required
None,
)
#set up the interface
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
#a scroll window is required for the terminal
scroller = Gtk.ScrolledWindow()
scroller.set_hexpand(True)
scroller.set_vexpand(True)
scroller.add(self.terminal)
box.pack_start(scroller, False, True, 2)
self.add(box)
#To get the command to automatically run
#a newline(\n) character is used at the end of the
#command string.
command_on_VTE(self,'''tty > /tmp/terminal_number\n''') # Get the terminal ID
# read the terminal ID
while not os.path.exists("/tmp/terminal_number"):
time.sleep(0.1)
with open('/tmp/terminal_number', 'r') as f:
self.VTE_redirect_path=f.readline()
os.remove('/tmp/terminal_number')
# this cleans the vte
os.system('''printf "\\033c" > {0}'''.format(self.VTE_redirect_path))
# this calls the exemple
threading.Thread(target=self.make_a_test).start()
def make_a_test(self):
os.system('''ls -laR /home/ > {rdc}
echo "-------- The listing ended -------
Note that the input of the commands are not printed
" > {rdc}'''.format(rdc=self.VTE_redirect_path))
win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
I haven't found a way of getting the Terminal ID with out passing for the creation of a temporary file. This could be skipped if there is some way to pass a variable from the VTE to the python script. Any help on this would be great!
In VTE you use terminal.feed("string")
See vte_terminal_feed.
With python Popen is the suggested method to execute commands.
If you are wanting to use commands then you should do this.
#Uncomment the next line to get the print() function of python 3
#from __future__ import print_function
import os
import subprocess
from subprocess import Popen
command = "echo \"something\""
env = os.environ.copy()
try:
po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
universal_newlines=True, env=env)
po.wait()
output, error_output = po.communicate()
if po.returncode:
print(error_output)
else:
print(output)
except OSError as e:
print('Execution failed:', e, file=sys.stderr)
If you want to use gtk with gtk vte then do this instead.
#place the following in a method of a vte instance
env = os.environ.copy()
try:
po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
universal_newlines=True, env=env)
po.wait()
output, error_output = po.communicate()
if po.returncode:
print(error_output)
else:
self.feed(output) #here you're printing to your terminal.
except OSError as e:
print('Execution failed:', e, file=sys.stderr)
For the finest control in a regular terminal you can try the cmd module. This will require that you produce your own prompt so it is a more specific option to get what you want.