banshee r5191 - in trunk/banshee: . tests tests/Analyzer tests/Performance



Author: gburt
Date: Mon Apr  6 23:57:39 2009
New Revision: 5191
URL: http://svn.gnome.org/viewvc/banshee?rev=5191&view=rev

Log:
2009-04-06  Gabriel Burt  <gabriel burt gmail com>

	* configure.ac:
	* tests/Analyzer/Analyzer.cs:
	* tests/Analyzer/Makefile.am:
	* tests/Makefile.am:
	* tests/Performance/Makefile.am:
	* tests/Performance/PerformanceTests.cs:
	* tests/compare-perf-results:
	* tests/test-perf: New scripts and tests for testing and comparing
	performance across commits.

Added:
   trunk/banshee/tests/Analyzer/
   trunk/banshee/tests/Analyzer/Analyzer.cs
   trunk/banshee/tests/Analyzer/Makefile.am
   trunk/banshee/tests/Performance/
   trunk/banshee/tests/Performance/Makefile.am
   trunk/banshee/tests/Performance/PerformanceTests.cs
   trunk/banshee/tests/compare-perf-results
   trunk/banshee/tests/test-perf
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/configure.ac
   trunk/banshee/tests/Makefile.am

Modified: trunk/banshee/configure.ac
==============================================================================
--- trunk/banshee/configure.ac	(original)
+++ trunk/banshee/configure.ac	Mon Apr  6 23:57:39 2009
@@ -172,6 +172,8 @@
 po/Makefile.in
 
 tests/Makefile
+tests/Analyzer/Makefile
+tests/Performance/Makefile
 
 extras/Makefile
 

Added: trunk/banshee/tests/Analyzer/Analyzer.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/Analyzer/Analyzer.cs	Mon Apr  6 23:57:39 2009
@@ -0,0 +1,177 @@
+//
+// Analyzer.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using System.Xml.Linq;
+using System.Collections.Generic;
+using System.IO;
+
+using Hyena;
+
+namespace Banshee.Tests
+{
+    public class Analyzer
+    {
+        public static void Main (string [] args)
+        {
+            if (args == null || args.Length == 0) {
+                Console.Error.WriteLine ("compare-perf-results [OVERALL-RESULTS-DIR | INDIVIDUAL-RESULTS-DIR1 ...]");
+                return;
+            }
+
+            if (args.Length == 1)
+                new Analyzer (args[0]);
+            else
+                new Analyzer (args);
+        }
+
+        private Analyzer (string results_dir) : this (System.IO.Directory.GetDirectories (results_dir))
+        {
+        }
+
+        private Analyzer (string [] results_dirs)
+        {
+            // Get the averaged tests for each directory
+            var all_tests = results_dirs.SelectMany<string, TestCase> (AveragedTests);
+
+            Console.Write ("{0,-42} ", ""); 
+            Console.WriteLine ("min   avg   max");
+
+            // Group by the test suite
+            var grouped_tests = all_tests.GroupBy (t => t.GroupName);
+            foreach (var group in grouped_tests) {
+
+                // Group by test name and calculate some stats
+                var unique_tests = group.GroupBy (t => t.Name);
+                //ConsoleCrayon.ForegroundColor = ConsoleColor.Gray;
+                Console.WriteLine ("{0}", group.Key);
+                //ConsoleCrayon.ResetColor ();
+
+                foreach (var tests in unique_tests) {
+                    var count = tests.Count ();
+                    var avg = tests.Average (t => t.Avg);
+                    var min = tests.Min (t => t.Min);
+                    var max = tests.Max (t => t.Max);
+
+                    Console.Write ("    {0,-36}", tests.Key);
+                    Console.WriteLine ();
+
+                    bool first = true;
+                    double first_min = 0, first_avg = 0, first_max = 0;
+                    foreach (var test in tests.OrderBy (t => t.RunTime)) {
+                        if (first) {
+                            first_min = test.Min;
+                            first_avg = test.Avg;
+                            first_max = test.Max;
+                            first = false;
+                        }
+
+                        Console.Write ("      {0,-36}", test.RunId);
+                        Console.Write (" {0,3:#00}   {1,3:#00}   {2,3:#00}", 100*test.Min/first_avg, 100*test.Avg/first_avg, 100*test.Max/first_avg);
+                        Console.Write ("     ({0,5:##0.00}   {1,5:##0.00}   {2,5:##0.00})", test.Min, test.Avg, test.Max);
+                        Console.WriteLine ();
+
+                        first = false;
+                    }
+
+                    Console.WriteLine ();
+                }
+
+                Console.WriteLine ();
+            }
+        }
+
+        private IEnumerable<TestCase> AveragedTests (string dir)
+        {
+            // Load all the test results in this directory
+            var tests = System.IO.Directory.GetFiles (dir)
+                            .Where (f => f.EndsWith (".xml"))
+                            .Select (f => XDocument.Load (f))
+                            .SelectMany<XDocument, TestCase> (TestCase.For)
+                            .ToArray ();
+
+            string [] run_info = File.ReadAllLines (dir + Path.DirectorySeparatorChar + "run-info");
+            string run_id = run_info[0];
+            string run_time = run_info[1];
+
+            // Return the avg runtime of each test
+            var grouped_tests = tests.GroupBy (t => t.Name);
+            foreach (var group in grouped_tests) {
+                var group_tests = group.ToList ();
+                if (group_tests.Any (t => t.Success)) {
+                    var min = group_tests.Where (t => t.Success).Min (t => t.Time);
+                    var max = group_tests.Where (t => t.Success).Max (t => t.Time);
+                    var avg = group_tests.Where (t => t.Success).Average (t => t.Time);
+
+                    var test = group_tests.Find (t => t.Success);
+                    test.Min = min;
+                    test.Max = max;
+                    test.Avg = avg;
+                    test.RunId = run_id;
+                    test.RunTime = run_time;
+                    yield return test;
+                }
+            }
+        }
+    }
+
+    public class TestCase {
+        public string FullName { get; set; }
+        public string RunId { get; set; }
+        public string RunTime { get; set; }
+        public double Time { get; set; }
+        public double Min { get; set; }
+        public double Max { get; set; }
+        public double Avg { get; set; }
+        public bool Success { get; set; }
+        public bool Executed { get; set; }
+        public int Asserts { get; set; }
+
+        public string Name {
+            get { return FullName.Substring (FullName.LastIndexOf (".") + 1); }
+        }
+
+        public string GroupName {
+            get { return FullName.Substring (0, FullName.LastIndexOf (".")); }
+        }
+
+        public static IEnumerable<TestCase> For (XDocument doc)
+        {
+            return doc.Descendants ()
+               .Where (d => d.Name == "test-case")
+               .Select (t => new TestCase {
+                    FullName = t.Attribute ("name").Value, 
+                    Time = Convert.ToDouble (t.Attribute ("time").Value),
+                    Success = Convert.ToBoolean (t.Attribute ("success").Value),
+                    Executed = Convert.ToBoolean (t.Attribute ("executed").Value),
+                    Asserts = Convert.ToInt32 (t.Attribute ("asserts").Value)
+                });
+        }
+    }
+}

Added: trunk/banshee/tests/Analyzer/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/Analyzer/Makefile.am	Mon Apr  6 23:57:39 2009
@@ -0,0 +1,13 @@
+include $(top_srcdir)/build/build.environment.mk
+
+ANALYZER_EXE = Analyzer.exe
+
+ALL_TARGETS = $(ANALYZER_EXE)
+
+$(ANALYZER_EXE): Analyzer.cs
+	$(MCS) -r:System.Xml.Linq -r:$(DIR_BIN)/Hyena.dll -debug+ -out:$@ $<
+
+all: $(ALL_TARGETS)
+
+CLEANFILES = *.exe *.mdb
+MAINTAINERCLEANFILES = Makefile.in

Modified: trunk/banshee/tests/Makefile.am
==============================================================================
--- trunk/banshee/tests/Makefile.am	(original)
+++ trunk/banshee/tests/Makefile.am	Mon Apr  6 23:57:39 2009
@@ -1,5 +1,8 @@
 include $(top_srcdir)/build/build.environment.mk
 
+SUBDIRS = \
+	Analyzer
+
 if ENABLE_TESTS
 
 TEST_ASSEMBLIES = \

Added: trunk/banshee/tests/Performance/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/Performance/Makefile.am	Mon Apr  6 23:57:39 2009
@@ -0,0 +1,13 @@
+include $(top_srcdir)/build/build.environment.mk
+
+PERFORMANCE_ASSEMBLY = Performance.dll
+
+ALL_TARGETS = $(PERFORMANCE_ASSEMBLY)
+
+$(PERFORMANCE_ASSEMBLY): PerformanceTests.cs
+	$(MCS) -target:library -r:$(DIR_BIN)/Hyena.dll $(NUNIT_LIBS) $(LINK_BANSHEE_THICKCLIENT_DEPS) -out:$@ $<
+
+all: $(ALL_TARGETS)
+
+CLEANFILES = *.dll *.mdb
+MAINTAINERCLEANFILES = Makefile.in

Added: trunk/banshee/tests/Performance/PerformanceTests.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/Performance/PerformanceTests.cs	Mon Apr  6 23:57:39 2009
@@ -0,0 +1,265 @@
+//
+// PerformanceTests.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Threading;
+using NUnit.Framework;
+
+using Hyena;
+using Hyena.Data;
+using Hyena.Query;
+using Hyena.CommandLine;
+
+using Banshee.Base;
+using Banshee.Collection;
+using Banshee.Query;
+using Banshee.ServiceStack;
+
+namespace Banshee.Tests
+{
+    [TestFixture]
+    public class PerformanceTests
+    {
+        const int NUM = 50;
+
+#region Reload tests
+
+        private void ReloadMusicLibrary (string filter)
+        {
+            ReloadMusicLibrary (filter, 1.0);
+        }
+
+        private void ReloadMusicLibrary (string filter, double runFactor)
+        {
+            music_library.FilterQuery = filter;
+            for (int i = 0; i < NUM*runFactor; i++) {
+                music_library.Reload ();
+            }
+        }
+
+        [Test]
+        public void Reload ()
+        {
+            ReloadMusicLibrary ("", .25);
+        }
+
+        [Test]
+        public void ReloadD ()
+        {
+            ReloadMusicLibrary ("d", .25);
+        }
+
+        [Test]
+        public void ReloadDave ()
+        {
+            ReloadMusicLibrary ("dave");
+        }
+
+        [Test]
+        public void ReloadByDave ()
+        {
+            ReloadMusicLibrary ("by:dave");
+        }
+
+        [Test]
+        public void ReloadFavorites ()
+        {
+            ReloadMusicLibrary ("rating>3");
+        }
+
+        [Test]
+        public void ReloadGenreRock ()
+        {
+            ReloadMusicLibrary ("genre:rock");
+        }
+
+#endregion
+
+        [Test]
+        public void ScrollLinear ()
+        {
+            music_library.FilterQuery = "";
+            int count = Math.Min (2500, music_library.FilteredCount);
+            bool any_null = false;
+
+            for (int i = 0; i < 6; i++) {
+                for (int j = 0; j < count; j++) {
+                    any_null |= music_library.TrackModel [j] == null;
+                }
+                music_library.DatabaseTrackModel.InvalidateCache (false);
+            }
+
+            Assert.IsFalse (any_null);
+        }
+
+#region Sort tests
+
+        private void SortMusicLibrary (QueryField field)
+        {
+            SortableColumn column = new SortableColumn (field);
+            music_library.FilterQuery = "";
+
+            for (int i = 0; i < NUM/2; i++) {
+                music_library.DatabaseTrackModel.Sort (column);
+                music_library.Reload ();
+            }
+        }
+
+        [Test]
+        public void SortTrack ()
+        {
+            SortMusicLibrary (BansheeQuery.TrackNumberField);
+        }
+
+        [Test]
+        public void SortArtist ()
+        {
+            SortMusicLibrary (BansheeQuery.ArtistField);
+        }
+
+        [Test]
+        public void SortRating ()
+        {
+            SortMusicLibrary (BansheeQuery.RatingField);
+        }
+
+        [Test]
+        public void SortLastPlayed ()
+        {
+            SortMusicLibrary (BansheeQuery.LastPlayedField);
+        }
+
+#endregion
+
+#region Helpers
+
+        private Thread main_thread;
+        private HeadlessClient client;
+        private Banshee.Library.MusicLibrarySource music_library;
+
+        [TestFixtureSetUp]
+        public void Setup ()
+        {
+            ApplicationContext.CommandLine = new CommandLineParser (new string [] { 
+                "--uninstalled",
+                Environment.GetEnvironmentVariable ("BANSHEE_DEV_OPTIONS") }, 0);
+            Log.Debugging = false;
+
+            /*Application.IdleHandler = delegate (IdleHandler handler) { handler (); return 0; };
+            Application.TimeoutHandler = delegate (uint milliseconds, TimeoutHandler handler) {
+                new System.Threading.Timer (delegate { handler (); }, null, milliseconds, Timeout.Infinite);
+                return 0;
+            };*/
+            Application.TimeoutHandler = RunTimeout;
+            Application.IdleHandler = RunIdle;
+            Application.IdleTimeoutRemoveHandler = IdleTimeoutRemove;
+            Application.Initialize ();
+
+            client = new HeadlessClient ();
+            main_thread = new Thread (RunBanshee);
+            main_thread.Start ();
+            while (!client.IsStarted) {}
+        }
+
+        private void RunBanshee ()
+        {
+            Gtk.Application.Init ();
+            ThreadAssist.InitializeMainThread ();
+            Application.PushClient (client);
+            Application.Run ();
+            music_library = ServiceManager.SourceManager.MusicLibrary;
+            client.Start ();
+        }
+
+        [TestFixtureTearDown]
+        public void Teardown ()
+        {
+            using (new Hyena.Timer ("Stopping Banshee")) {
+                ThreadAssist.ProxyToMain (Application.Shutdown);
+            }
+            main_thread.Join ();
+            main_thread = null;
+        }
+
+        protected uint RunTimeout (uint milliseconds, TimeoutHandler handler)
+        {
+            return GLib.Timeout.Add (milliseconds, delegate { return handler (); });
+        }
+
+        protected uint RunIdle (IdleHandler handler)
+        {
+            return GLib.Idle.Add (delegate { return handler (); });
+        }
+
+        protected bool IdleTimeoutRemove (uint id)
+        {
+            return GLib.Source.Remove (id);
+        }
+
+#endregion
+
+    }
+
+    public class SortableColumn : ISortableColumn
+    {
+        QueryField field;
+        SortType sort_type;
+
+        public SortableColumn (QueryField field)
+        {
+            this.field = field;
+        }
+
+        public string SortKey { get { return field.Name; } }
+
+        public SortType SortType {
+            get { return sort_type; }
+            set { sort_type = value; }
+        }
+
+        public Hyena.Query.QueryField Field { get { return field; } }
+
+        public string Id { get { return field.Name; } }
+    }
+
+    public class HeadlessClient : Client
+    {
+        public override string ClientId {
+            get { return "Headless"; }
+        }
+
+        public HeadlessClient ()
+        {
+        }
+
+        public void Start ()
+        {
+            OnStarted ();
+        }
+    }
+}

Added: trunk/banshee/tests/compare-perf-results
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/compare-perf-results	Mon Apr  6 23:57:39 2009
@@ -0,0 +1 @@
+MONO_PATH=../bin/ mono Analyzer/Analyzer.exe $@

Added: trunk/banshee/tests/test-perf
==============================================================================
--- (empty file)
+++ trunk/banshee/tests/test-perf	Mon Apr  6 23:57:39 2009
@@ -0,0 +1,165 @@
+#!/usr/bin/perl
+
+#
+# test-perf
+#
+# Author:
+#   Gabriel Burt <gburt novell com>
+#
+# Copyright (C) 2009 Novell, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+use strict;
+
+chomp(my $pwd = `pwd`);
+chdir "../bin" || die "couldn't cd ../bin";
+
+my $RUNS_PER_TEST = 3;
+my $ENV_OPTIONS = "TZ=America/Chicago LC_ALL=it_IT LANG=it_IT";
+my $original_rev = current_rev();
+
+sub current_rev {
+    my $current_rev = `git rev-parse \ \{0\};`;
+    chomp($current_rev);
+    return $current_rev;
+}
+
+sub usage {
+    print "test-perf [--name=NAME] [SHORT-NAME=GIT-REV | GIT-REV | GIT-REV-EXPR]...\n\n";
+    print "  NAME specifies the directory that the NUnit xml results will be placed in\n";
+    print "  SHORT-NAME lets you alias a git revision\n\n";
+    print "  GIT-REV and GIT-REV-EXPR must be parsable by git rev-parse\n\n";
+    print "  Examples:\n\n";
+    print "     test-perf --name=a-vs-b a=HEAD~3 b=34e934\n";
+    print "     test-perf HEAD~3 34e934 # same as above, just without nice aliases\n";
+    print "     test-perf\n";
+    exit;
+}
+
+my $run_name = "results";
+my %revisions;
+my @ordered_revisions;
+my $rev_count = 0;
+foreach my $in (@ARGV) {
+    if ($in =~ m/--help/) {
+        usage ();
+    } elsif ($in =~ m/^--name=(\S+)$/) {
+        $run_name = $1;
+    } elsif ($in =~ m/^(\S+)=(\S+)$/) {
+        my $rev = `git rev-parse $2`;
+        chomp $rev;
+        $revisions{$1} = $rev;
+        push @ordered_revisions, $1;
+        $rev_count++;
+    } else {
+        my @expanded = `git rev-parse $in`;
+        foreach my $rev (@expanded) {
+            chomp $rev;
+            my $key = length(@expanded) == 1 ? $in : $rev;
+            $revisions{$key} = $rev;
+            push @ordered_revisions, $key;
+            $rev_count++;
+        }
+    }
+}
+
+if ($rev_count == 0) {
+    usage ();
+}
+
+print "Will test:\n";
+foreach my $key (@ordered_revisions) {
+    my $val = $revisions{$key};
+    if ($key eq $val) {
+        print "  $val\n";
+    } else {
+        print "  $val ($key)\n";
+    }
+}
+print "\n";
+
+my $results_dir = "$pwd/$run_name";
+print "Warning: results dir $results_dir already exists\n\n" if -d $results_dir;
+`mkdir -p $results_dir`;
+
+# Backup the database so we can restore it after each test
+`cp ~/.config/banshee-1/banshee.db ~/.config/banshee-1/banshee.db.bak`;
+
+foreach my $rev_name (@ordered_revisions) {
+    print "* $rev_name\n";
+
+    my $rev = $revisions{$rev_name};
+    my $rev_dir = "$results_dir/$rev_name";
+
+    if (-d $rev_dir) {
+        print "  - Removing existing results dir ($rev_dir)\n";
+        unlink $rev_dir;
+    }
+    mkdir $rev_dir;
+
+    # TODO output these as well ?
+    # load
+    # hwinfo --cpu
+    # hwinfo --memory
+    # $(BUILD_VENDOR_ID)
+    # $(BUILD_HOST_OS)
+    # $(BUILD_HOST_CPU)
+    # $(BUILD_TIME)
+    # put a chronologically-ordered identifier for this commit into its result dir (run-info file)
+    my $alias = $rev_name eq $rev ? "" : " $rev_name";
+    my $info = `git rev-list -n 1 --pretty=format:"%ai %h %at" $rev | grep -v commit`;
+    $info =~ s/^(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\S+)$/$1 $2$alias\n$3/;
+    chomp($info);
+    `echo "$info" > $rev_dir/run-info`;
+
+    chdir "..";
+
+    my $cur = current_rev ();
+    if ($rev ne current_rev()) {
+        print "  - Checking out\n";
+        `git checkout $rev >/dev/null`;
+        print "  - Building $rev_name\n";
+    } else {
+        print "  - Building $rev_name\n";
+    }
+
+    my $make_ret = `make`;
+    chdir "bin";
+    `cp ../tests/Performance/Performance.dll .`;
+
+    print "  - Testing $rev_name\n";
+    #foreach my $asm (glob("*.dll"))
+    foreach my $asm (glob("Performance.dll")) {
+        for (my $i = 0; $i < $RUNS_PER_TEST; $i++) {
+            `$ENV_OPTIONS nunit-console2 -nologo -noshadow -xml=$rev_dir/$i-$asm.xml $asm 2>/dev/null`;
+            `cp ~/.config/banshee-1/banshee.db.bak ~/.config/banshee-1/banshee.db`;
+        }
+    }
+
+    print "\n\n";
+}
+
+if (current_rev () ne $original_rev) {
+    `git checkout $original_rev`;
+}
+
+print "Output is in $run_name/\n";



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]