For building and maintaining packages in Fedora:
– https://fedoraproject.org/wiki/Using_Fedora_GIT
– http://fedoraproject.org/wiki/Bodhi
For building and maintaining packages in Fedora:
– https://fedoraproject.org/wiki/Using_Fedora_GIT
– http://fedoraproject.org/wiki/Bodhi
# exes: python-2.7-x32, pyqt4-2.7-x32, py2exe-2.7-x32
# run: cd C:\Users\admin\Desktop\fedora-arm-installer
# files: setup.py, MSVCP90.dll
# run: C:\Python27\python.exe setup.py py2exe
import sys,os
from distutils.core import setup
import py2exe
os.system("rd /s /q .\\build")
os.system("rd /s /q .\\dist")
os.system("rd /s /q .\\fedora-arm-installer-0.0.0-0.x32")
a=open("fedora-arm-installer","r")
b=open("fedora-arm-installer-2","w")
for l in a.readlines():
m = l
m = m.replace("sys.stderr","#sys.stderr")
m = m.replace("proglist.append(progcomd)","proglist.append(re.sub('fedora-arm-installer-2.exe$','helper.exe',progcomd))")
b.write(m)
b.close()
a.close()
os.system("copy fedora-arm-installer-2 helper /y")
setup(console=['helper'], options={"py2exe":{"includes":["sip"]}})
setup(windows=['fedora-arm-installer-2'], options={"py2exe":{"includes":["sip"]}})
os.system("md .\\dist\\data")
os.system("xcopy .\\data .\\dist\\data")
os.system("rename .\\dist fedora-arm-installer-0.0.0-0.x32")
Edit: Updated the setup.py script above to remove the command line window
# exes: python-2.7-x32, pyqt4-2.7-x32, py2exe-2.7-x32
# run: cd C:\Users\admin\Desktop\fedora-arm-installer
# files: setup.py, MSVCP90.dll
# run: C:\Python27\python.exe setup.py py2exe
import sys,os
from distutils.core import setup
import py2exe
os.system("rd /s /q .\\build")
os.system("rd /s /q .\\dist")
a=open("fedora-arm-installer","r")
b=open("fedora-arm-installer-2","w")
for l in a.readlines():
m = l.replace("sys.stderr","#sys.stderr")
b.write(m)
b.close()
a.close()
setup(console=['fedora-arm-installer'], options={"py2exe":{"includes":["sip"]}})
#setup(windows=['fedora-arm-installer-2'], options={"py2exe":{"includes":["sip"]}})
os.system("md .\\dist\\data")
os.system("xcopy .\\data .\\dist\\data")
This script will follow the general procedure:
* List the latest tagged (non-inherited) packages from the arch being followed
* Download and import any of the non-arch detected packages
* Sort all missing builds by their creation timestamp and order them to be qued
* Loop thru the missing package list and download and que each build
A simple server-side script to help reduce the size of the Koji sessions table:
#!/bin/bash pd=$(echo $(date "+%s") - 1800 | bc) ; echo "$pd" ; psql koji -c "delete from sessions where extract(epoch from update_time) < $pd and master != 0;" while true do pd=$(echo $(date "+%s") - 1800 | bc) ; echo "$pd" ; psql koji -c "delete from sessions where expired = 't' and extract(epoch from update_time) < $pd;" sleep 2400 done
A simple script to re-que the latest failed build tasks in case of a build-root breakage:
#!/bin/bash
let x="0"
let l="50 * $1"
while [ $x -lt $l ]
do
echo "[$x]"
for t in `curl -sL "$1/koji/tasks?start=${x}&state=failed&view=flat&method=build&order=-completion_time" | grep -Eiv "pcre|libssh|glib2|glibc" | grep -i 'taskinfo.taskID=[0-9]*' | sed -e 's/^.*taskinfo.taskID=\([0-9]*\).*$/\1/g'`
do
echo " [$t]"
koji -s "$1/kojihub" resubmit --nowait "$t"
done
let x="$x + 50"
done
* Connect both devices to a common WiFi AP and determine their IP addresses (Windows/Nexus)
* Download a capable SSH/SFTP/SCP server app that also allows you to setup a capable login user (Nexus)
* Download and run “dokan-sshfs” and then connect to and mount the phone as a “U:\” drive (Windows)
* Run the “syncplay.js” wscript below to sync a smart playlist called “recent” to the phone (Windows)
var iTunesApp = WScript.CreateObject("iTunes.Application");
var mainLibrary = iTunesApp.LibrarySource;
var playlists = mainLibrary.Playlists;
var numPlaylists = playlists.Count;
var fileSys = WScript.CreateObject("Scripting.FileSystemObject");
while (numPlaylists != 0)
{
var currPlaylist = playlists.Item(numPlaylists);
if (currPlaylist.Name == "recent")
{
var playlistTracks = currPlaylist.Tracks;
var numTracks = playlistTracks.Count;
WScript.Echo("[" + currPlaylist.Name + ":" + numTracks + "]");
while (numTracks != 0)
{
var sourceTrack = playlistTracks.Item(numTracks);
var targetTrack = ("U:\\sdcard\\Music\\" + fileSys.GetBaseName(sourceTrack.Location) + "." + fileSys.GetExtensionName(sourceTrack.Location));
var sourceSize = fileSys.GetFile(sourceTrack.Location).Size;
var targetSize = 0;
if (fileSys.FileExists(targetTrack))
{
targetSize = fileSys.GetFile(targetTrack).Size;
}
//WScript.Echo("[" + sourceTrack.Name + ":" + sourceTrack.Location + ":" + targetTrack + "]");
if (sourceSize != targetSize)
{
fileSys.CopyFile(sourceTrack.Location, targetTrack);
}
numTracks--;
}
//add check to remove uneeded songs
//create a playlist xml file
//force device refresh
WScript.Echo("Done");
}
numPlaylists--;
}
The WordPress.com stats helper monkeys prepared a 2012 annual report for this blog.
Here’s an excerpt:
600 people reached the top of Mt. Everest in 2012. This blog got about 2,900 views in 2012. If every person who reached the top of Mt. Everest viewed this blog, it would have taken 5 years to get that many views.
So we’ve fired up a new Koji setup to facilitate our future builds of ARMv6hl capable packages. The new site can be reached and tracked here ( http://japan.proximity.on.ca/koji/ ). Right now, it is attempting to catch up by “cleanly” and natively building Fedora Linux 17 for ARMv6hl for the first time. In the future, we may run the koji-shadow build script which matches the build process of the secondary && primary arch’s and employs a smarter que’ing technique.
Note:
For a new arch, you'll have to patch Koji as well. For example, you can find any references to armhfp/armv7hl and so on and replace them with armv6hl using this command: rpm -qa | grep -Ei '(rpm|yum|koji)' | while read p ; do echo "$p" ; rpm -ql "$p" | xargs grep -i "armhfp" 2> /dev/null ; done
This (brute-force) build script can be run concurrently with other copies of itself at the same time.
que.sh
#!/bin/bash while true do x=1 last="a" pkgn="b" tskl=`curl -sL 'http://japan.proximity.on.ca/koji/tasks?view=flat&state=active&method=build&order=-id' | grep -i 'through' | sed -e 's/^.*through [0-9]* of //g' -e 's/<.*$//g' | head -n 1` if [ "$tskl" == "" ] then tskl=0 fi while [ $tskl -lt $1 ] do pkgn=`head -n "$x" pkgs.txt | tail -n 1` if [ "$pkgn" == "$last" ] then exit fi #echo "$pkgn" if [ ! -f "$pkgn.src.rpm" ] then echo " building [$pkgn]...." koji -s 'http://arm.koji.fedoraproject.org/kojihub' download-build --arch=src --topurl='http://arm.koji.fedoraproject.org/' "$pkgn" koji -s 'http://japan.proximity.on.ca/kojihub' build f17 "$pkgn.src.rpm" --nowait let tskl="$tskl + 1" fi last="$pkgn" let x="$x + 1" done sleep 30 done
This script below will reset the failed build attempts after each run is completed.
rst.sh
#!/bin/bash
rm -fv *.src.rpm
for tagd in `koji -s 'http://japan.proximity.on.ca/kojihub' list-tagged f17 --quiet --latest --inherit | awk '{ print $1 }'`
do
touch "${tagd}.src.rpm"
done
And since Koji seems to suck (no offence) at managing its sessions table, this script will clear out any expired sessions which are more than 10 minutes old so the table doesn’t become huge and slow.
exp.sh
#!/bin/bash
while true
do
psql koji -c "select update_time from sessions where expired = 't';" | cat | grep -i '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' | while read date
do
a=`date --date="$date" "+%s"`
b=`date "+%s"`
let c="($b - $a) / (60 * 10)"
if [ $c -gt 0 ]
then
echo "deleting [$date] exp [$c] from [`date`]"
psql koji -c "delete from sessions where expired = 't' and update_time = '$date';"
fi
done
sleep 300
done
Was doing some late-night Slashdot reading and came across an article submission which had a blog post about a facebook employee who had been fired. Although it seems like personal rant, there are some interesting points which give insight on how companies think about employees.
http://okdork.com/2012/09/29/why-i-got-fired-from-facebook-a-100-million-dollar-lesson/
Quoting:
“When you hire people there are three types of employees:
1- Grower. Someone who starts when the company is small and improves / adapts their skills as the company scales.
2- Show-er. Someone who can be good for the company where they are now but NOT where they are going.
3- Veteran. They’ve done it before and it’s second nature for them to teach you how to do it in your company.”
…
“Firing:
1- It stings the person WAY more than the company. I thought every day that the company missed me but I’ve learned they just keep going on with business. AND (UN)FORTUNATELY most businesses get better. So be stern when letting someone go but be reasonable and thoughtful to how it must feel. I encourage everyone to get fired once so they know that feeling. It’s unbelievable and something to definitely learn from.
2- EVERYONE is replaceable. You are NOT special and there is guaranteed someone better than you on this planet. So be the opposite, find the way to be invaluable where you work. This doesn’t mean locking things into you but opening things up so you are trusted and subsequently valued more.
3- Most people when they get let go, they know it’s time. They may not want to accept what their subconscious tells them but they know it’s right and it opens them up to something better. Instead of throwing them away, help guide / work with them to see what is their true calling and better suited for them.”
edit
I also came across another article which highlighted a video about motivation which I had posted before on this blog. It tries to explain why we do what we do in this open source world: http://www.youtube.com/watch?v=u6XAPnuFjJc ( http://www.ted.com/talks/dan_pink_on_motivation.html )
Note: These steps assume you have a gcc compiler capable of producing the correct assembly instructions for the intended new arch
Step 1: Add the necessary architecture definitions
/usr/lib/rpm/platform/armv6hl-linux/macros
... %optflags -O2 -g -march=armv6 -mfloat-abi=hard -mfpu=vfp %__isa_name armv6hl ...
/usr/lib/rpm/{,redhat}/{rpmrc,macros}
...
optflags: armv6hl -O2 -g -march=armv6 -mfloat-abi=hard -mfpu=vfp
arch_canon: armv6hl: armv6hl 12
buildarchtranslate: armv6hl: armv6hl
arch_compat: armv6hl: armv7hnl
buildarch_compat: armv6hl: armv7hnl
...
%arm armv3l armv4b armv4l armv4tl armv5tel armv5tejl armv6l armv6hl armv7l armv7hl armv7hnl
...
optflags: armv6hl %{__global_cflags} -march=armv6 -mfloat-abi=hard -mfpu=vfp
buildarchtranslate: armv6hl: armv7hnl
...
/usr/lib/python2.7/site-packages/rpmUtils/arch.py
... "armv6hl": "armv7hnl", ...
Step 2: Compile the latest version of gcc for your related arch using rpmbuild (--target armv6hl)
Step 3: Modify mock to hijack && inject these new files into all future build roots
/usr/sbin/mock
...
def do_rebuild(config_opts, chroot, srpms):
...
chroot.init()
ldst = (chroot.basedir+"/root"+"/usr/lib/rpm/platform")
import shutil
shutil.copytree("/usr/lib/rpm/platform/armv6hl-linux",ldst+"/armv6hl-linux")
os.system("for f in /usr/lib/rpm/{,redhat}/{rpmrc,macros} ; do cp -fv \"$f\" \""+chroot.basedir+"/root/$f\" ; done")
lcmd = ("/bin/rpm --force --ignorearch --nodeps --root "+chroot.basedir+"/root/ -i /repo/gcc-4.7.0-5.fc17/*.rpm")
os.system(lcmd)
chroot.build(srpm, timeout=config_opts['rpmbuild_timeout'])
...
Step 4: Build glibc and all other needed packages using mock (use a helper shell script loop && make sure to patch rpm/yum/redhat-rpm-config later)
/etc/mock/f17v6.cfg
... config_opts['target_arch'] = 'armv6hl' ...
Step 4.5.0: rpm C code (unified diff patch)
rpm-x.x/lib/rpmrc.c
...
+# if defined(__linux__) && defined(__arm__)
+ {
+ if (strcmp(un.machine, "armv7l") == 0 ) {
+ if (has_neon() && has_hfp())
+ strcpy(un.machine, "armv7hnl");
+ else if (has_hfp())
+ strcpy(un.machine, "armv7hl");
+ }
+ if (strcmp(un.machine, "armv6l") == 0 ) {
+ if (has_neon() && has_hfp())
+ strcpy(un.machine, "armv6hnl");
+ else if (has_hfp())
+ strcpy(un.machine, "armv6hl");
+ strcpy(un.machine, "armv6hl");
+ }
+ }
+# endif /* arm*-linux */
+
...
Step 4.5.1: yum Python script (mod)
yum-x.x/{yum/misc.py,rpmUtils/arch.py}
...
os.uname().replace("armv6l","armv6hl").replace("armv7l","armv6hl").replace("armv7hl","armv6hl")
...
Step 5: Install a core set of packages needed for a minimal boot (use a capable host/arch)
compose.sh
#!/bin/bash
if [ "$repo" == "" -o "$root" == "" ] ; then exit 1 ; fi
setenforce 0
for pkgn in 'acl' 'attr' 'audit' 'authconfig' 'basesystem' 'bash' 'binutil' 'bzip' 'ca-certificate' 'chkconfig' 'cpio' 'coreutil' 'cracklib' 'cryptsetup' 'curl' '.*curses' 'cyrus-sasl' 'db4' 'dbus' 'dbus-glib' 'diffutil' 'dracut' 'e2fsprog' 'elfutil' 'expat' 'fedora-release' '/file' 'findutil' 'fipscheck' 'gamin' 'gawk' 'gcc' 'gdbm' 'generic-release' 'glib' 'gmp' 'gnupg2' 'gpgme' 'grep' 'gzip' 'hardlink' 'hostname' 'hwdata' 'initscript' 'iproute' 'iptable' 'iputil' '.*kernel' 'keyutil' 'kmod' 'krb5' 'libassuan' 'libcap.*' 'libdb' 'libedit' 'libffi' 'libgcrypt' 'libgpg-error' 'libidn' 'libpwquality' 'libse' 'libssh2' 'libus' 'libut' 'libxml2' 'linux-atm' 'logrotate' 'lua' 'lvm2' 'mingetty' 'net-tool' 'newt' 'nspr' '/nss.*' '/openss' 'openldap' 'pam' 'passwd' 'pcre' 'pinentry' 'pkgconfig' 'popt' 'procps' 'psmisc' 'pth' 'pygpgme' 'python' 'python-chardet' 'python-iniparse' 'python-kitchen' 'python-pycurl' 'python-urlgrabber' 'readline' '/rpm' 'sed' '/setup' 'shadow-util' 'shared-mime-info' 'slang' 'sqlite' 'syslog' 'systemd' 'sysvinit' 'tcp_wrapper' 'texinfo' 'tzdata' 'udev' 'ustr' 'util-linux' 'xz' 'yum' 'yum-metadata-parser' 'yum-util' 'zlib' ; do fill=`find $repo -type f | grep -i "/[^/-]*$pkgn[^/-]*-[^/-]*-[^/-]*/[^/]*.rpm$" | grep -Eiv '(-debuginfo-|.src.rpm)'` ; if [ "$fill" == "" ] ; then echo "FOF $pkgn" 1>&2 ; continue ; fi ; echo "$fill" ; done | sort | uniq | grep -Eiv '/(audispd-plugins|audit-libs-devel|audit-libs-static|cmirror|cpp|cryptsetup-devel|cryptsetup-python|cyrus-sasl-sql|dbus-glib-devel|dracut-fips|emacs-libidn|gcc|glib2-devel|glib2-static|glibc-devel|glibc-headers|glibc-static|glibc-utils|gnupg2-smime|krb5-server|libcap-ng-devel|libgcrypt-devel|libgcj|libgfortran|libgudev1-devel|libitm|libmudflap|libselinux-python|libsemanage-python|libuser-devel|linux-atm-libs-devel|lvm2-cluster|newt-devel|newt-static|openldap-devel|openldap-servers|openldap-servers-sql|openssh-askpass|openssh-ldap|openssl-devel|openssl-perl|openssl-static|pam_|passwdqc|policycoreutils-python|policycoreutils-sandbox|python[0-9]*-debug|python[0-9]*-devel|python[0-9]*-test|python[0-9]*-tkinter|python[0-9]*-tools|rpm-build-[0-9]|rpm-cron|rpm-devel|rpm-sign|rpmdevtools|rpmlint|rsyslog-gnutls|rsyslog-libdbi|rsyslog-mysql|rsyslog-pgsql|rsyslog-relp|rsyslog-snmp|rsyslog-udpspoof|setuptool|slang-slsh|sqlite-tcl|systemd-analyze|texinfo-tex|tkinter|yum-cron|yum-plugin-changelog|yum-plugin-local|yum-plugin-puppetverify|yum-plugin-refresh-updatesd|yum-plugin-tmprepo)[^/-]*-[^/]*$' > pkglist.txt
#for p in $(rpm --force --ignorearch --root $root/ -i $(cat pkglist.txt | grep -Eiv '(gtk|gui|qt|x11)') 2>&1 | awk '{ print $1","$NF }' | sort | uniq) ; do a=$(echo "$p" | cut -d ',' -f 1) ; b=$(echo "$p" | cut -d ',' -f 2) ; q=$(repoquery --whatprovides "$a" | head -n 1) ; r=$(repoquery -qi "$q" | grep -i '^source') ; echo "[$b] -> [$a] -> [$q] -> [$r]" ; done
rpm --force --ignorearch --nodeps --root $root/ -i $(cat pkglist.txt | grep -Eiv '(gtk|gui|qt|x11)') x2
rm -frv $root/usr/share/*doc*
cat << EOF > $root/etc/fstab
LABEL="rootfs" / ext4 defaults,noatime 1 1
LABEL="boot" /boot vfat noauto,comment=systemd.automount 1 2
EOF
cat << EOF > $root/etc/sysconfig/network
HOSTNAME=raspiv6hl.local
EOF
cat << EOF > $root/etc/resolv.conf
nameserver 4.2.2.1
EOF
echo 'utmp:x:22:' >> $root/etc/group
echo 'PS1="[\u@\h: \w]# "' > $root/root/.bashrc
chmod 755 $root/root/.bashrc
ln -s .bashrc $root/root/.profile
#raspberrypi
sed -i 's|root:.*:|root:$6$KW0GGbE5$zlEB9.PbHVh8kmXj1WMFGLJGwwthhU4oXn2oNxHZllbUSzTsVhTZ9jts8RC7uicuUCWyrsZ1e2yEj4ErDLOHQ/:15525:0:99999:7:::|' $root/etc/shadow
rm -fv $root/etc/systemd/system/default.target && ln -s /usr/lib/systemd/system/multi-user.target $root/etc/systemd/system/default.target
Step 6: Boot the new Fedora ARM Linux system
I haven’t blogged in a while because it has taken literally weeks upon weeks of trying to bootstrap ARMv6HL for Fedora, pretty much by myself (plus hints from my boss Chris Tyler). I am not a programmer! But anyway, I think it’s coming along to some degree at least (remind me to always respect the complexity of gcc && glibc). In addition to this, I am planning on working with Seneca college for another year and also, this is officially the first time I’ve hit the gym!!! My friend and co-worker Andrew Greene, who has been working hard on various tasks, decided to show me around the machines today which was pretty cool and I already feel a bit better for myself after having gone (hopefully I’ll keep it up). I also have thank my co-workers Jordan and Paul for encouraging me to go in the first place, along with the other life advice they’ve given me. In addition, we got a new team member named Dmitry who’s been pretty much looking after our build farm and making sure all the machines remain up for all the remote users who depend on its availability.
And on a last note, my friend Leopold Antonio Martinez (who’s been like my best friend for life) and I are planning on looking for places to live. He’s helped me out constantly in the past and been there for me all the time. This next step should help me separate from my Italian parents and gain some independence! Thanks Lee 🙂
Anyway, enough of my ranting, here’s hoping for another productive year!
Johnny S.
So now that I’m working full time hours, I’d like to monitor the ARM computers in our build farm more closely and in a nicer manner. These series of scripts (d3 js and Twitter Bootstrap) are based on a whole bunch of other scripts like: Koji Client Command, Icinga, and my own check_koji.pl nagios plugin. The result looks like the following:
farm.py - A python script that gets the needed info being displayed
#!/usr/bin/python
import getpass
import os
import re
import sys
import time
import subprocess
import urllib2, base64
sys.stdout.write("Username: ")
sys.stdout.flush()
user = sys.stdin.readline().strip()
spwd = getpass.unix_getpass()
while (1):
indx = 0
buil = {}
node = ""
link = ""
node += ("{\"name\":\"Hosts\",\"size\":0,\"group\":0,\"info\":\"root\"}")
link += ("{\"source\":0,\"target\":0}")
indx += 1
bsfs = base64.encodestring("%s:%s" % (user, spwd)).replace("\n", "")
try:
requ = urllib2.Request(sys.argv[1] + "/cgi-bin/status.cgi?host=all")
requ.add_header("Authorization", "Basic %s" % bsfs)
resu = urllib2.urlopen(requ)
webp = resu.read().replace("\0","").replace("\t","").replace("\r","").replace("\n","")
except:
print("urllib...")
time.sleep(60)
continue
webp = re.sub("<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>", "\n<beg line='true'>", webp)
for line in webp.split("\n"):
if (re.match("^.*>Koji Stat<.*$", line, re.I)):
host = re.sub("^.*host=([^&]+).*$", "\\1", line).strip()
line = re.sub("^.+(OK|WARNING|UNKNOWN|CRITICAL).+[0-9]+[0-9]+-[0-9]+[0-9]+-[0-9]+[0-9]+[0-9]+[0-9]+[ ]+[0-9]+[0-9]+:[0-9]+[0-9]+:[0-9]+[0-9]+(.+)$", "<td>\\1</td>\\2", line).strip()
line = line.replace("<TD", "\t<TD")
part = line.split("\t")
for x in range(0, len(part)):
part[x] = re.sub("<[^>]*>", " ", part[x]).strip()
stat = part[0]
info = part[3]
colr = 3
if (stat == "CRITICAL"):
colr = 3
if (stat == "WARNING"):
colr = 2
if (stat == "OK"):
colr = 1
info = "OK"
buil[host] = indx
node += (",\n{\"name\":\"%s [%s]\",\"size\":1,\"group\":%d,\"info\":\"%s\"}" % (host, stat, colr, info))
link += (",\n{\"source\":%d,\"target\":%d}" % (0, indx))
indx += 1
pipe = subprocess.Popen(["/usr/bin/koji", "-s", sys.argv[2], "list-tasks"], stdout=subprocess.PIPE)
for line in pipe.stdout.readlines():
line = line.replace("\t", " ").strip()
line = re.sub(" [ ]+", " ", line)
regx = re.match("^([^ ]+) .* (CANCELED|FAILED|OPEN|CLOSED) .* build[ ]+([^ ]+)[ ]+([^ ]+)$", line, re.I)
if (regx):
task = regx.group(4)
host = regx.group(3).replace("[","").replace("]","")
stat = regx.group(2)
info = regx.group(1)
colr = 4
if (stat == "CANCELED"):
colr = 3
if (stat == "FAILED"):
colr = 3
if (stat == "OPEN"):
colr = 5
if (stat == "CLOSED"):
colr = 1
if (not host in buil.keys()):
buil[host] = indx
node += (",\n{\"name\":\"%s [%s]\",\"size\":1,\"group\":%d,\"info\":\"%s\"}" % (host, "REMOTE", 6, "N/A"))
link += (",\n{\"source\":%d,\"target\":%d}" % (0, indx))
indx += 1
node += (",\n{\"name\":\"%s [%s]\",\"size\":1,\"group\":%d,\"info\":\"%s\"}" % (task, stat, colr, info))
link += (",\n{\"source\":%d,\"target\":%d}" % (buil[host], indx))
indx += 1
fobj = open("force.json", "w")
fobj.write("{\n\"nodes\":[\n%s\n],\n\"links\":[\n%s\n]\n}\n" % (node, link))
fobj.close()
print("sleeping...")
time.sleep(45)
force.js - Some JavaScript that initializes the force directed graph
//var width = 640, height = 560, distance = 64;
var width = 1024, height = 900, distance = 128;
var sizes = [10, 10];
// blue, green, yellow, red, purple, orange, blue
var colors = ["rgba(30, 120, 180, 1)", "rgba(0, 155, 0, 1)", "rgba(250, 195, 0, 1)", "rgba(206, 22, 32, 1)", "rgba(100, 0, 155, 1)", "rgba(255, 160, 0, 1)", "rgba(30, 120, 180, 1)"];
var nodes = "", force = null, svg = null, mous = {x:0,y:0};
function over()
{
try { var l = force.nodes(); }
catch(err) { var l = []; }
for (var i in l)
{
var r = sizes[l[i].size];
var a = (l[i].x - r);
var b = (l[i].x + r);
var c = (l[i].y - r);
var d = (l[i].y + r);
if ((a <= mous.x) && (mous.x <= b) && (c <= mous.y) && (mous.y <= d))
{
document.getElementById("info").innerHTML = ("<b>" + l[i].name + "</b> :: " + l[i].info);
}
}
setTimeout("over()", 0.15 * 1000);
}
function move(e)
{
var obj = document.getElementsByTagName("svg");
if (obj.length > 0)
{
var pt = obj[0].createSVGPoint();
var scr = obj[0].getScreenCTM();
var inv = scr.inverse();
pt.x = e.clientX; pt.y = e.clientY;
mous = pt.matrixTransform(inv);
}
}
function tick()
{
try { force.start(); }
catch(err) { console.log("tick"); }
setTimeout("tick();", 3 * 1000);
}
function loop()
{
d3.json("force.json", function(json) {
var stri = JSON.stringify(json);
if (stri == nodes)
{
return;
}
//console.log(nodes+"!="+stri);
nodes = stri;
document.getElementById("chart").innerHTML = "";
force = d3.layout.force()
.charge(-512)
.linkDistance(distance)
.size([width, height]);
svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height);
force
.nodes(json.nodes)
.links(json.links)
.start();
var l = force.nodes();
document.getElementById("list").innerHTML = "";
for (var i in l)
{
if (l[i].name.match(/^.*cdot.*(WARNING|CRITICAL|UNKNOWN).*$/i))
{
document.getElementById("list").innerHTML += ("<div class='alert alert-error' style='margin: 5px;'><b>" + l[i].name + "</b> :: " + l[i].info + "</div>");
}
}
var link = svg.selectAll("line.link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(4); });
var node = svg.selectAll("circle.node")
.data(json.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return sizes[d.size]; })
.style("fill", function(d) { return colors[d.group]; })
.call(force.drag);
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
setTimeout("loop();", 15 * 1000);
}
loop();
tick();
over();
window.onmousemove = move;
force.html - The main page that puts everything together
<html>
<head>
<title>Farm Visual</title>
<script type="text/javascript" src="d3.v2.js"></script>
<style>
circle.node
{
stroke: #000;
stroke-width: 2.0px;
}
line.link
{
stroke: #999;
stroke-opacity: 0.75;
}
svg
{
border: 1px solid black;
}
#info, #list
{
white-space: nowrap;
}
</style>
<link href="/scripts/bootstrap/css/bootstrap.css" rel="stylesheet">
<link href="/scripts/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<script src="/scripts/jquery.js"></script>
<script src="/scripts/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<center>
<table width="100%">
<tr><td colspan="2"><div id='info' class='alert alert-info' style='margin: 5px;'><b>Build Farm Status</b></div></td></tr>
<tr><td><div class="gallery" id="chart" style="margin: 5px;"></div></td>
<td valign="top" width="100%"><div id="list"></div></td></tr>
</table>
</center>
<link href="force.css" rel="stylesheet" type="text/css" />
<script src="force.js" type="text/javascript"></script>
</body>
</html>
So we needed some Firstboot modules for the F17 Rasp Pi release which would allow the user to customize similar features to what the Anaconda installer would ask you. This is mainly due to the fact that a lot of ARM devices don’t yet have an Anaconda based install method yet.
I helped to create a simple script which could assist in the automation and creation of ARM-based images after standardized tools like kickstart, lorax, and livemedia-creator have been used. The problem is that some ARM devices (like OMAP) require there to be a FAT partition and filesystem listed first which contains proper binaries to assist with the initial booting process. Since x86 machines don’t have this requirement, their creation tools don’t include an option to help set this up. The python script listed below helps to take an outputted image and just modify it slightly to meet these requirements for us automatically. Here is an example of the output along with its source code.
# fdisk -l F18-panda-20121218.img
...
Device Boot Start End Blocks Id System
F18-panda-20121218.img1 * 2048 411647 204800 6 FAT16
F18-panda-20121218.img2 411648 1435647 512000 82 Linux swap / Solaris
F18-panda-20121218.img3 1435648 5941247 2252800 83 Linux
# ./livemedia-modifier --image=F18-panda-20121218.img --platform=omap
...
loop deleted : /dev/loop0
Modification completed successfully!
# fdisk -l F18-panda-20121218.img
...
Device Boot Start End Blocks Id System
F18-panda-20121218.img1 * 2048 411647 204800 c W95 FAT32 (LBA)
F18-panda-20121218.img2 411648 1435647 512000 82 Linux swap / Solaris
F18-panda-20121218.img3 1435648 5941247 2252800 83 Linux
#
Source Code (Git Hub)
Binary Program (Fedora People)
Fedora Wiki
So my friends have been encouraging me to try and meet new people on the Internet through some various online dating sites. Creating a profile was a good start but I quickly found myself getting really distracted by all the profile pictures when I should be reading the profile text instead. I decided to create a simple little grease-monkey script to remove all of the pics on the site and therefore force me to read one’s profile instead. Here’s the result:
// ==UserScript==
// @name okcp
// @namespace gm-dev
// @include http://www.okcupid.com/*
// @version 1
// ==/UserScript==
var pics = document.getElementsByTagName("img");
for (var pici in pics)
{
try
{
var wide = pics[pici].width;
var high = pics[pici].height;
pics[pici].src = "http://142.204.133.82/tmp/images/qmt.png";
pics[pici].onmouseover = "";
pics[pici].width = wide;
pics[pici].height = high;
}
catch(e)
{
console.log("pic error?");
}
}
var side = document.getElementById("left_bar");
if (side)
{
side.style.width = "200px";
}
My colleague Jordan was able to use WIX to create a MSI Windows Installer application for the FAII app. You can find the file and blog post with this URL The Whacky Wonderful World of WiX.
Following up on my work with the Koji Icinga/Nagios based monitoring system for our Fedora ARM machines: A screenshot of how it looks along with a GM script that helped to make it look like that. The Perl script I made in an earlier post checks for some of the following errors that could cause a Koji builder to fail. And on an semi-related note, if you’d like to follow our build progress, I’m currently testing a Twitter script posting here: http://twitter.com/fedoraarmstats
// ==UserScript==
// @name icinga
// @namespace icinga-dev
// @include http://hongkong.proximity.on.ca/icinga/cgi-bin/status.cgi?host=all*
// @version 1
// ==/UserScript==
var cnmatch = false, globflag = false;
var tablelist = document.getElementsByTagName("table");
var bodylist = [], rowlist = [], collist = [];
var regxobjc = new RegExp("Koji Stat", "g");
for (var tableitem in tablelist)
{
try { cnmatch = tablelist[tableitem].className.match(/^.*status.*$/); }
catch(erro) { cnmatch = false; }
if (cnmatch)
{
bodylist = tablelist[tableitem].childNodes;
for (var bodyitem in bodylist)
{
try { cnmatch = (bodylist[bodyitem].nodeName.toLowerCase() == "tbody"); }
catch(erro) { cnmatch = false; }
if (cnmatch)
{
var lastclas = "", lastvalu = "";
rowlist = bodylist[bodyitem].childNodes;
for (var rowitem in rowlist)
{
var rowflag = true;
var colnumb = 0, colobjc = null;
try { cnmatch = (rowlist[rowitem].nodeName.toLowerCase() == "tr"); }
catch(erro) { cnmatch = false; }
if (cnmatch)
{
collist = rowlist[rowitem].childNodes;
for (var colitem in collist)
{
try { cnmatch = (collist[colitem].nodeName.toLowerCase() == "td"); }
catch(erro) { cnmatch = false; }
if (cnmatch)
{
if (colnumb == 0)
{
if (collist[colitem].innerHTML != "")
{
lastvalu = collist[colitem].innerHTML;
}
else
{
colobjc = collist[colitem];
}
}
if (colnumb == 1)
{
if (!collist[colitem].innerHTML.match(regxobjc))
{
rowflag = false;
}
}
lastclas = collist[colitem].className;
++colnumb;
}
}
if ((colobjc != null) && (colnumb > 3))
{
lastvalu = lastvalu.replace(/class=['"]status[^'"]+['"]/g, lastclas);
colobjc.innerHTML = lastvalu;
colobjc.className = lastclas;
}
}
if ((rowflag == false) || ((0 < colnumb) && (colnumb < 4)))
{
try { rowlist[rowitem].style.display = "none"; }
catch(erro) { cnmatch = false; }
}
}
}
}
}
}