banshee r5191 - in trunk/banshee: . tests tests/Analyzer tests/Performance
- From: gburt svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r5191 - in trunk/banshee: . tests tests/Analyzer tests/Performance
- Date: Mon, 6 Apr 2009 23:57:40 +0000 (UTC)
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]