Merge remote-tracking branch 'hbons/master' into gettext-cs
Conflicts: .gitignore .gitmodules SparkleLib/Git/SparkleFetcherGit.cs SparkleLib/Hg/SparkleRepoHg.cs SparkleLib/SparkleConfig.cs SparkleLib/SparkleFetcherBase.cs SparkleLib/SparkleListenerIrc.cs SparkleShare/SparkleBubblesController.cs SparkleShare/SparkleControllerBase.cs SparkleShare/SparkleStatusIcon.cs
This commit is contained in:
commit
b98c4ee5fb
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -27,6 +27,8 @@ aclocal.m4
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
|
/bin/
|
||||||
|
SparkleShare/Mac/bin
|
||||||
install-sh
|
install-sh
|
||||||
libtool
|
libtool
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
basedirs = build help SmartIrc4net SparkleLib data po
|
basedirs = build help SparkleLib data po
|
||||||
|
|
||||||
SUBDIRS = $(basedirs) $(GUISUBDIRS)
|
SUBDIRS = $(basedirs) $(GUISUBDIRS)
|
||||||
DIST_SUBDIRS = $(basedirs) SparkleShare
|
DIST_SUBDIRS = $(basedirs) SparkleShare
|
||||||
|
|
22
NEWS
22
NEWS
|
@ -1,3 +1,25 @@
|
||||||
|
0.6.0 for Linux and Mac (Sun Dec 25 2011):
|
||||||
|
|
||||||
|
Hylke:
|
||||||
|
- Several fixes for annoying bugs and crashes
|
||||||
|
- Fix freeze on quit on Mac
|
||||||
|
- Show project and history size in the event log
|
||||||
|
|
||||||
|
|
||||||
|
0.4.2 for Linux and Mac (Fri Dec 2 2011):
|
||||||
|
Hylke: Fix crash trying to add a project
|
||||||
|
|
||||||
|
|
||||||
|
0.4.1 for Linux and Mac (Tue Nov 29 2011):
|
||||||
|
Hylke: Just some small tweaks and fixes:
|
||||||
|
|
||||||
|
- Bundle git with the Mac application
|
||||||
|
- Warn about potential global gitignore files
|
||||||
|
- Remove SmartIrc4Net
|
||||||
|
- Build system fixes
|
||||||
|
- Code cleanups
|
||||||
|
|
||||||
|
|
||||||
0.4.0 for Linux and Mac (Sun Nov 12 2011):
|
0.4.0 for Linux and Mac (Sun Nov 12 2011):
|
||||||
Hylke: It has been a while since the last release. Since so many
|
Hylke: It has been a while since the last release. Since so many
|
||||||
things changed, and it being (softly) incompatible with 0.2, I decided
|
things changed, and it being (softly) incompatible with 0.2, I decided
|
||||||
|
|
145
README
145
README
|
@ -1,145 +0,0 @@
|
||||||
# SparkleShare
|
|
||||||
|
|
||||||
SparkleShare is a collaboration and sharing tool that is designed to keep
|
|
||||||
things simple and to stay out of your way. It allows you to instantly sync
|
|
||||||
with any Git repository you have access to.
|
|
||||||
|
|
||||||
SparkleShare currently works on Linux and Mac. A Windows port and mobile
|
|
||||||
device support are planned for the future.
|
|
||||||
|
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
SparkleShare is free software and licensed under the GNU GPLv3 or later. You
|
|
||||||
are welcome to change and redistribute it under certain conditions. For more
|
|
||||||
information see the LICENSE file or visit http://www.gnu.org/licenses/gpl-3.0.html
|
|
||||||
|
|
||||||
|
|
||||||
# Run on Linux
|
|
||||||
|
|
||||||
Requirements:
|
|
||||||
|
|
||||||
- git >= 1.7.0
|
|
||||||
- gtk-sharp2
|
|
||||||
- gvfs
|
|
||||||
- intltool
|
|
||||||
- libnotify
|
|
||||||
- mono-core >= 2.8
|
|
||||||
- notify-sharp
|
|
||||||
- nautilus-python
|
|
||||||
- openssh
|
|
||||||
- pygtk
|
|
||||||
- webkitgtk
|
|
||||||
- webkit-sharp
|
|
||||||
|
|
||||||
Run the service, either click the SparkleShare launcher or:
|
|
||||||
|
|
||||||
$ sparkleshare start
|
|
||||||
|
|
||||||
You can stop the service via the graphical interface or by typing:
|
|
||||||
|
|
||||||
$ sparkleshare stop
|
|
||||||
|
|
||||||
For help:
|
|
||||||
|
|
||||||
$ sparkleshare --help
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
SparkleShare creates its own RSA keypair in ~/config/sparkleshare/ and uses
|
|
||||||
that for authentication. Please mind this if you're planning to set up your
|
|
||||||
own server by hand.
|
|
||||||
|
|
||||||
|
|
||||||
# Build on Linux
|
|
||||||
|
|
||||||
Installing the build dependencies on Debian or Ubuntu:
|
|
||||||
|
|
||||||
$ sudo apt-get install gtk-sharp2 mono-runtime mono-devel monodevelop \
|
|
||||||
libndesk-dbus1.0-cil-dev nant libnotify-cil-dev libgtk2.0-cil-dev mono-gmcs \
|
|
||||||
libwebkit-cil-dev intltool libtool python-nautilus libndesk-dbus-glib1.0-cil-dev
|
|
||||||
|
|
||||||
For Ubuntu libappindicator support, run the following before building:
|
|
||||||
|
|
||||||
$ sudo apt-get install libappindicator0.1-cil-dev
|
|
||||||
|
|
||||||
On Fedora:
|
|
||||||
|
|
||||||
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
|
|
||||||
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
|
|
||||||
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool \
|
|
||||||
gnome-doc-utils
|
|
||||||
|
|
||||||
You can build and install SparkleShare like this:
|
|
||||||
|
|
||||||
$ ./configure --prefix=/usr (or ./autogen.sh if you build from the repository)
|
|
||||||
$ make
|
|
||||||
$ sudo make install
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
Use '--prefix=/usr' if you want the Nautilus extension to work.
|
|
||||||
|
|
||||||
|
|
||||||
# Run on Mac
|
|
||||||
|
|
||||||
Just double-click the SparkleShare bundle.
|
|
||||||
|
|
||||||
|
|
||||||
# Build on Mac
|
|
||||||
|
|
||||||
Install Xcode, the Mono Framework, MonoDevelop and the MonoMac plugin (you can find it in MonoDevelop => Add-in Manager).
|
|
||||||
|
|
||||||
You may need to adjust some environment variables to let the build environment tools find mono:
|
|
||||||
|
|
||||||
$ export PATH=/Library/Frameworks/Mono.framework/Versions/Current/bin:$PATH
|
|
||||||
$ export PKG_CONFIG=/Library/Frameworks/Mono.framework/Versions/Current/bin/pkg-config
|
|
||||||
$ export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig
|
|
||||||
|
|
||||||
Install git, automake, and intltool using MacPorts:
|
|
||||||
|
|
||||||
$ sudo port install git-core automake intltool
|
|
||||||
|
|
||||||
Start the first part of the build:
|
|
||||||
|
|
||||||
$ ./autogen.sh --enable-gtkui=no
|
|
||||||
$ make
|
|
||||||
|
|
||||||
Now that you have compiled the libraries, open 'SparkleShare/Mac/SparkleShare.sln' in
|
|
||||||
MonoDevelop and start the build.
|
|
||||||
|
|
||||||
To create the SparkleShare.app, make sure the project is focused and select Project from the menu bar
|
|
||||||
and click "Create Mac Installer...". Make sure to select "Don't link assemblies".
|
|
||||||
|
|
||||||
Save the SparkleShare.app somewhere. Paste the contents of
|
|
||||||
the following file in SparkleShare.app/Contents/MonoBundle/config:
|
|
||||||
https://raw.github.com/gist/1aeffa61bac73fc08eca/0c0f09ef9e36864c35f34fd5e8bf4f99886be193/gistfile1.txt
|
|
||||||
|
|
||||||
Copy /Library/Frameworks/Mono.framework/Versions/Current/lib/libintl.dylib
|
|
||||||
to SparkleShare.app/Contents/Resources
|
|
||||||
|
|
||||||
Now you should have a working bundle that you can run.
|
|
||||||
|
|
||||||
|
|
||||||
# Info
|
|
||||||
|
|
||||||
Official website:
|
|
||||||
http://www.sparkleshare.org/
|
|
||||||
|
|
||||||
Source code:
|
|
||||||
http://github.com/SparkleShare/
|
|
||||||
|
|
||||||
IRC Channel:
|
|
||||||
#sparkleshare on irc.gnome.org
|
|
||||||
|
|
||||||
Wiki:
|
|
||||||
http://github.com/hbons/SparkleShare/wiki/
|
|
||||||
|
|
||||||
Report issues:
|
|
||||||
http://github.com/hbons/SparkleShare/issues/
|
|
||||||
|
|
||||||
Translation project:
|
|
||||||
http://www.transifex.net/projects/p/sparkleshare/
|
|
||||||
|
|
||||||
|
|
||||||
Now have fun and create cool things together! :)
|
|
162
README.md
Normal file
162
README.md
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# SparkleShare
|
||||||
|
|
||||||
|
SparkleShare is a collaboration and sharing tool that is designed to keep
|
||||||
|
things simple and to stay out of your way. It allows you to instantly sync
|
||||||
|
with any Git repository you have access to.
|
||||||
|
|
||||||
|
SparkleShare currently works on Linux and Mac. A Windows port and mobile
|
||||||
|
device support are planned for the future.
|
||||||
|
|
||||||
|
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/21770/SparkleShare-Sharing-work-made-easy)
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
SparkleShare is free software and licensed under the GNU GPLv3 or later. You
|
||||||
|
are welcome to change and redistribute it under certain conditions. For more
|
||||||
|
information see the LICENSE file or visit http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
|
||||||
|
## Run on Linux
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- git >= 1.7.0
|
||||||
|
- gtk-sharp2
|
||||||
|
- gvfs
|
||||||
|
- intltool
|
||||||
|
- libnotify
|
||||||
|
- mono-core >= 2.8
|
||||||
|
- notify-sharp
|
||||||
|
- nautilus-python
|
||||||
|
- openssh
|
||||||
|
- pygtk
|
||||||
|
- webkitgtk
|
||||||
|
- webkit-sharp
|
||||||
|
|
||||||
|
Run the service, either click the SparkleShare launcher or:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sparkleshare start
|
||||||
|
```
|
||||||
|
|
||||||
|
You can stop the service via the graphical interface or by typing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sparkleshare stop
|
||||||
|
```
|
||||||
|
|
||||||
|
For help:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sparkleshare --help
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
|
||||||
|
SparkleShare creates its own RSA keypair in `~/config/sparkleshare/` and uses
|
||||||
|
that for authentication. Please mind this if you're planning to set up your
|
||||||
|
own server by hand.
|
||||||
|
|
||||||
|
|
||||||
|
## Build on Linux
|
||||||
|
|
||||||
|
### Install build dependencies
|
||||||
|
|
||||||
|
#### Debian or Ubuntu (apt):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo apt-get install gtk-sharp2 mono-runtime mono-devel monodevelop \
|
||||||
|
libndesk-dbus1.0-cil-dev nant libnotify-cil-dev libgtk2.0-cil-dev mono-mcs mono-gmcs \
|
||||||
|
libwebkit-cil-dev intltool libtool python-nautilus libndesk-dbus-glib1.0-cil-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fedora (yum):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
|
||||||
|
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
|
||||||
|
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool \
|
||||||
|
gnome-doc-utils
|
||||||
|
```
|
||||||
|
|
||||||
|
For Ubuntu `libappindicator` support, install the following package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo apt-get install libappindicator0.1-cil-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then build and install SparkleShare like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./configure --prefix=/usr (or ./autogen.sh if you build from the repository)
|
||||||
|
$ make
|
||||||
|
$ sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Use `--prefix=/usr` if you want the Nautilus extension to work.
|
||||||
|
|
||||||
|
|
||||||
|
## Run on Mac
|
||||||
|
|
||||||
|
Just double-click the SparkleShare bundle.
|
||||||
|
|
||||||
|
|
||||||
|
## Build on Mac
|
||||||
|
|
||||||
|
Install <tt>Xcode</tt>, the <tt>Mono</tt> Framework, <tt>MonoDevelop</tt> and the <tt>MonoMac</tt> plugin
|
||||||
|
(you can find it in <tt>MonoDevelop</tt> => <tt>Add-in Manager</tt>).
|
||||||
|
|
||||||
|
You may need to adjust some environment variables to let the build environment tools find mono:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ export PATH=/Library/Frameworks/Mono.framework/Versions/Current/bin:$PATH
|
||||||
|
$ export PKG_CONFIG=/Library/Frameworks/Mono.framework/Versions/Current/bin/pkg-config
|
||||||
|
$ export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Install <tt>git</tt>, <tt>automake</tt>, and <tt>intltool</tt> using <tt>MacPorts</tt>:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo port install git-core automake intltool
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the first part of the build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./autogen.sh --enable-gtkui=no
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that you have compiled the libraries, open `SparkleShare/Mac/SparkleShare.sln` in
|
||||||
|
MonoDevelop and start the build.
|
||||||
|
|
||||||
|
To create the <tt>SparkleShare.app</tt>, make sure the project is focused and select Project from the menu bar
|
||||||
|
and click <tt>"Create Mac Installer..."</tt>. Make sure to select <tt>"Don't link assemblies"</tt>.
|
||||||
|
|
||||||
|
Save the <tt>SparkleShare.app</tt> somewhere. Paste the contents of
|
||||||
|
the following file in `SparkleShare.app/Contents/MonoBundle/config`:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://raw.github.com/gist/1aeffa61bac73fc08eca/0c0f09ef9e36864c35f34fd5e8bf4f99886be193/gistfile1.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `/Library/Frameworks/Mono.framework/Versions/Current/lib/libintl.dylib` to `SparkleShare.app/Contents/Resources`
|
||||||
|
|
||||||
|
|
||||||
|
Now you should have a working bundle that you can run.
|
||||||
|
|
||||||
|
|
||||||
|
## Info
|
||||||
|
|
||||||
|
|||
|
||||||
|
|-----------------------------------:|:--------------------------|
|
||||||
|
| **Official website**: | http://www.sparkleshare.org/ |
|
||||||
|
| **Source code**: | http://github.com/SparkleShare/ |
|
||||||
|
| **IRC Channel**: | #sparkleshare on irc.gnome.org |
|
||||||
|
| **Wiki**: | http://github.com/hbons/SparkleShare/wiki/ |
|
||||||
|
| **Report issues**: | http://github.com/hbons/SparkleShare/issues/ |
|
||||||
|
| **Translation project**: | http://www.transifex.net/projects/p/sparkleshare/ |
|
||||||
|
|
||||||
|
|
||||||
|
Now have fun and create cool things together! :)
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 036e2233aea9bd3b4a30f8c5136daff0187eb5ec
|
|
|
@ -94,6 +94,9 @@ namespace SparkleLib {
|
||||||
double percentage = 1.0;
|
double percentage = 1.0;
|
||||||
Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled);
|
Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
DateTime last_change = DateTime.Now;
|
||||||
|
TimeSpan change_interval = new TimeSpan (0, 0, 0, 1);
|
||||||
|
|
||||||
while (!this.git.StandardError.EndOfStream) {
|
while (!this.git.StandardError.EndOfStream) {
|
||||||
string line = this.git.StandardError.ReadLine ();
|
string line = this.git.StandardError.ReadLine ();
|
||||||
Match match = progress_regex.Match (line);
|
Match match = progress_regex.Match (line);
|
||||||
|
@ -107,7 +110,7 @@ namespace SparkleLib {
|
||||||
// the "Receiving objects" stage which we count as the last 80%
|
// the "Receiving objects" stage which we count as the last 80%
|
||||||
if (line.Contains ("|"))
|
if (line.Contains ("|"))
|
||||||
// "Receiving objects" stage
|
// "Receiving objects" stage
|
||||||
number = (number / 100 * 75 + 20);
|
number = (number / 100 * 80 + 20);
|
||||||
else
|
else
|
||||||
// "Compressing objects" stage
|
// "Compressing objects" stage
|
||||||
number = (number / 100 * 20);
|
number = (number / 100 * 20);
|
||||||
|
@ -116,19 +119,20 @@ namespace SparkleLib {
|
||||||
if (number >= percentage) {
|
if (number >= percentage) {
|
||||||
percentage = number;
|
percentage = number;
|
||||||
|
|
||||||
// FIXME: for some reason it doesn't go above 95%
|
if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) {
|
||||||
base.OnProgressChanged (percentage);
|
base.OnProgressChanged (percentage);
|
||||||
|
last_change = DateTime.Now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Threading.Thread.Sleep (100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.git.WaitForExit ();
|
this.git.WaitForExit ();
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "Exit code " + this.git.ExitCode.ToString ());
|
SparkleHelpers.DebugInfo ("Git", "Exit code " + this.git.ExitCode.ToString ());
|
||||||
|
|
||||||
|
|
||||||
if (this.git.ExitCode != 0) {
|
if (this.git.ExitCode != 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
InstallConfiguration ();
|
InstallConfiguration ();
|
||||||
InstallExcludeRules ();
|
InstallExcludeRules ();
|
||||||
|
@ -137,9 +141,33 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override string [] Warnings {
|
||||||
|
get {
|
||||||
|
SparkleGit git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||||
|
"config --global core.excludesfile");
|
||||||
|
|
||||||
|
git.Start ();
|
||||||
|
|
||||||
|
// Reading the standard output HAS to go before
|
||||||
|
// WaitForExit, or it will hang forever on output > 4096 bytes
|
||||||
|
string output = git.StandardOutput.ReadToEnd ().Trim ();
|
||||||
|
git.WaitForExit ();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty (output)) {
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new string [] {
|
||||||
|
string.Format ("You seem to have configured a system ‘gitignore’ file. " +
|
||||||
|
"This may interfere with SparkleShare.\n({0})", output)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Stop ()
|
public override void Stop ()
|
||||||
{
|
{
|
||||||
if (this.git != null) {
|
if (this.git != null && !this.git.HasExited) {
|
||||||
this.git.Kill ();
|
this.git.Kill ();
|
||||||
this.git.Dispose ();
|
this.git.Dispose ();
|
||||||
}
|
}
|
||||||
|
@ -179,22 +207,11 @@ namespace SparkleLib {
|
||||||
// Add a .gitignore file to the repo
|
// Add a .gitignore file to the repo
|
||||||
private void InstallExcludeRules ()
|
private void InstallExcludeRules ()
|
||||||
{
|
{
|
||||||
string exclude_rules_file_path = SparkleHelpers.CombineMore (
|
DirectoryInfo info = Directory.CreateDirectory (SparkleHelpers.CombineMore (
|
||||||
this.target_folder, ".git", "info", "exclude");
|
this.target_folder, ".git", "info"));
|
||||||
|
|
||||||
string directory = Path.GetDirectoryName(exclude_rules_file_path);
|
string exlude_rules_file_path = Path.Combine (info.FullName, "exclude");
|
||||||
|
TextWriter writer = new StreamWriter (exlude_rules_file_path);
|
||||||
if (directory == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(directory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (exclude_rules_file_path);
|
|
||||||
|
|
||||||
// gedit and emacs
|
// gedit and emacs
|
||||||
writer.WriteLine ("*~");
|
writer.WriteLine ("*~");
|
||||||
|
@ -257,6 +274,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class SparkleGit : Process {
|
public class SparkleGit : Process {
|
||||||
|
|
||||||
public SparkleGit (string path, string args) : base ()
|
public SparkleGit (string path, string args) : base ()
|
||||||
|
|
|
@ -26,15 +26,8 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public class SparkleRepoGit : SparkleRepoBase {
|
public class SparkleRepoGit : SparkleRepoBase {
|
||||||
|
|
||||||
private string exlude_rules_file_path;
|
|
||||||
private string ExclusionBlock = "#Temporary Exclusions";
|
|
||||||
|
|
||||||
public SparkleRepoGit (string path, SparkleBackend backend) :
|
public SparkleRepoGit (string path, SparkleBackend backend) :
|
||||||
base (path, backend) {
|
base (path, backend) { }
|
||||||
// Set exclude file path
|
|
||||||
exlude_rules_file_path = SparkleHelpers.CombineMore (
|
|
||||||
LocalPath, ".git", "info", "exclude");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private string identifier = null;
|
private string identifier = null;
|
||||||
|
@ -66,6 +59,34 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override List<string> ExcludePaths {
|
||||||
|
get {
|
||||||
|
List<string> rules = new List<string> ();
|
||||||
|
rules.Add (Path.DirectorySeparatorChar + ".git");
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override double Size {
|
||||||
|
get {
|
||||||
|
return CalculateSize (
|
||||||
|
new DirectoryInfo (LocalPath)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override double HistorySize {
|
||||||
|
get {
|
||||||
|
return CalculateSize (
|
||||||
|
new DirectoryInfo (Path.Combine (LocalPath, ".git"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string [] UnsyncedFilePaths {
|
public override string [] UnsyncedFilePaths {
|
||||||
get {
|
get {
|
||||||
List<string> file_paths = new List<string> ();
|
List<string> file_paths = new List<string> ();
|
||||||
|
@ -144,16 +165,73 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public override bool SyncUp ()
|
public override bool SyncUp ()
|
||||||
{
|
{
|
||||||
|
if (AnyDifferences) {
|
||||||
Add ();
|
Add ();
|
||||||
|
|
||||||
string message = FormatCommitMessage ();
|
string message = FormatCommitMessage ();
|
||||||
Commit (message);
|
Commit (message);
|
||||||
|
}
|
||||||
|
|
||||||
SparkleGit git = new SparkleGit (LocalPath, "push origin master");
|
|
||||||
|
SparkleGit git = new SparkleGit (LocalPath,
|
||||||
|
"push --progress " + // Redirects progress stats to standarderror
|
||||||
|
"origin master");
|
||||||
|
|
||||||
|
git.StartInfo.RedirectStandardError = true;
|
||||||
git.Start ();
|
git.Start ();
|
||||||
git.StandardOutput.ReadToEnd ();
|
|
||||||
|
double percentage = 1.0;
|
||||||
|
Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
DateTime last_change = DateTime.Now;
|
||||||
|
TimeSpan change_interval = new TimeSpan (0, 0, 0, 1);
|
||||||
|
|
||||||
|
while (!git.StandardError.EndOfStream) {
|
||||||
|
string line = git.StandardError.ReadLine ();
|
||||||
|
Match match = progress_regex.Match (line);
|
||||||
|
string speed = "";
|
||||||
|
double number = 0.0;
|
||||||
|
|
||||||
|
if (match.Success) {
|
||||||
|
number = double.Parse (match.Groups [1].Value);
|
||||||
|
|
||||||
|
// The pushing progress consists of two stages: the "Compressing
|
||||||
|
// objects" stage which we count as 20% of the total progress, and
|
||||||
|
// the "Writing objects" stage which we count as the last 80%
|
||||||
|
if (line.StartsWith ("Compressing")) {
|
||||||
|
// "Compressing objects" stage
|
||||||
|
number = (number / 100 * 20);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// "Writing objects" stage
|
||||||
|
number = (number / 100 * 80 + 20);
|
||||||
|
|
||||||
|
if (line.Contains ("|")) {
|
||||||
|
speed = line.Substring (line.IndexOf ("|") + 1).Trim ();
|
||||||
|
speed = speed.Replace (", done.", "").Trim ();
|
||||||
|
speed = speed.Replace ("i", "");
|
||||||
|
speed = speed.Replace ("KB/s", "ᴋʙ/s");
|
||||||
|
speed = speed.Replace ("MB/s", "ᴍʙ/s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number >= percentage) {
|
||||||
|
percentage = number;
|
||||||
|
|
||||||
|
if (percentage == 100.0)
|
||||||
|
percentage = 99.0;
|
||||||
|
|
||||||
|
if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) {
|
||||||
|
base.OnSyncProgressChanged (percentage, speed);
|
||||||
|
last_change = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
|
|
||||||
if (git.ExitCode == 0)
|
if (git.ExitCode == 0)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
|
@ -163,10 +241,63 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public override bool SyncDown ()
|
public override bool SyncDown ()
|
||||||
{
|
{
|
||||||
SparkleGit git = new SparkleGit (LocalPath, "fetch -v");
|
SparkleGit git = new SparkleGit (LocalPath, "fetch --progress");
|
||||||
|
|
||||||
|
git.StartInfo.RedirectStandardError = true;
|
||||||
git.Start ();
|
git.Start ();
|
||||||
|
|
||||||
|
double percentage = 1.0;
|
||||||
|
Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
DateTime last_change = DateTime.Now;
|
||||||
|
TimeSpan change_interval = new TimeSpan (0, 0, 0, 1);
|
||||||
|
|
||||||
|
while (!git.StandardError.EndOfStream) {
|
||||||
|
string line = git.StandardError.ReadLine ();
|
||||||
|
Match match = progress_regex.Match (line);
|
||||||
|
string speed = "";
|
||||||
|
double number = 0.0;
|
||||||
|
|
||||||
|
if (match.Success) {
|
||||||
|
number = double.Parse (match.Groups [1].Value);
|
||||||
|
|
||||||
|
// The fetching progress consists of two stages: the "Compressing
|
||||||
|
// objects" stage which we count as 20% of the total progress, and
|
||||||
|
// the "Receiving objects" stage which we count as the last 80%
|
||||||
|
if (line.StartsWith ("Compressing")) {
|
||||||
|
// "Compressing objects" stage
|
||||||
|
number = (number / 100 * 20);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// "Writing objects" stage
|
||||||
|
number = (number / 100 * 80 + 20);
|
||||||
|
|
||||||
|
if (line.Contains ("|")) {
|
||||||
|
speed = line.Substring (line.IndexOf ("|") + 1).Trim ();
|
||||||
|
speed = speed.Replace (", done.", "").Trim ();
|
||||||
|
speed = speed.Replace ("i", "");
|
||||||
|
speed = speed.Replace ("KB/s", "ᴋʙ/s");
|
||||||
|
speed = speed.Replace ("MB/s", "ᴍʙ/s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number >= percentage) {
|
||||||
|
percentage = number;
|
||||||
|
|
||||||
|
if (percentage == 100.0)
|
||||||
|
percentage = 99.0;
|
||||||
|
|
||||||
|
if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) {
|
||||||
|
base.OnSyncProgressChanged (percentage, speed);
|
||||||
|
last_change = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
|
|
||||||
if (git.ExitCode == 0) {
|
if (git.ExitCode == 0) {
|
||||||
Rebase ();
|
Rebase ();
|
||||||
return true;
|
return true;
|
||||||
|
@ -216,6 +347,7 @@ namespace SparkleLib {
|
||||||
if (value) {
|
if (value) {
|
||||||
if (!File.Exists (unsynced_file_path))
|
if (!File.Exists (unsynced_file_path))
|
||||||
File.Create (unsynced_file_path).Close ();
|
File.Create (unsynced_file_path).Close ();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
File.Delete (unsynced_file_path);
|
File.Delete (unsynced_file_path);
|
||||||
}
|
}
|
||||||
|
@ -233,177 +365,16 @@ namespace SparkleLib {
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes staged");
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes staged");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new file to be ignored
|
|
||||||
public override bool AddExclusionRule (FileSystemEventArgs args) {
|
|
||||||
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
exclusions = ReadExclusionRules();
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the local exclusions section
|
|
||||||
bool added = false;
|
|
||||||
for(int i = 0; i < exclusions.Count; i++) {
|
|
||||||
string entry = exclusions[i];
|
|
||||||
if(entry.Equals(ExclusionBlock)) {
|
|
||||||
// add a new exclusion rule containing a file path
|
|
||||||
exclusions.Insert(i + 1, RelativePath);
|
|
||||||
added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For compability to existing repos:
|
|
||||||
* Add a "#Temporary Exclusions"-Block to the
|
|
||||||
* ignore file in order to recognize this
|
|
||||||
* exclude rules later on
|
|
||||||
*/
|
|
||||||
if(!added) {
|
|
||||||
exclusions.Add(ExclusionBlock);
|
|
||||||
exclusions.Add(RelativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write exceptions list back to file
|
|
||||||
return WriteExclusionRules(exclusions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether a specific rule exists in the exclusion file
|
|
||||||
public override bool ExclusionRuleExists(FileSystemEventArgs args) {
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
// Read rules from temporary block only
|
|
||||||
exclusions = ReadExclusionRules(true);
|
|
||||||
|
|
||||||
foreach(string entry in exclusions) {
|
|
||||||
if(entry.Equals(RelativePath)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Cannot determine whether an exclusion rule for " +
|
|
||||||
args.FullPath + " already exists or not.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove file from exclusion list when they are readable again
|
|
||||||
public override bool RemoveExclusionRule(FileSystemEventArgs args) {
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
exclusions = ReadExclusionRules();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Removing a rule should only apply to rules in the "Temporary Exclusion"-block.
|
|
||||||
* Therefore we first read until reaching the block and then remove the rule.
|
|
||||||
*
|
|
||||||
* We cannot use ReadExclusionRules(true) here since we write all lines back
|
|
||||||
* to the file. This would result in a crippled exclusion file.
|
|
||||||
*/
|
|
||||||
bool BlockReached = false;
|
|
||||||
foreach(string entry in exclusions) {
|
|
||||||
if(entry.Equals(ExclusionBlock)) {
|
|
||||||
BlockReached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove this rule
|
|
||||||
if(BlockReached && entry.Equals(RelativePath)) {
|
|
||||||
exclusions.Remove(entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteExclusionRules(exclusions);
|
|
||||||
} catch {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Unable to remove exclusion rule for entry " + RelativePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads the exclusion rules file into a string list
|
|
||||||
private List<String> ReadExclusionRules() {
|
|
||||||
|
|
||||||
List<String> exclusions = new List<String>();
|
|
||||||
TextReader reader = new StreamReader (exlude_rules_file_path);;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while(reader.Peek() > -1) {
|
|
||||||
exclusions.Add(reader.ReadLine().TrimEnd());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Reading from exclusion file failed: " + e.Message);
|
|
||||||
return new List<String>();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if(reader != null) {
|
|
||||||
reader.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exclusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads rules only from temporary exclusion block
|
|
||||||
private List<String> ReadExclusionRules(bool TempOnly) {
|
|
||||||
if(TempOnly) {
|
|
||||||
bool ForceRead = false;
|
|
||||||
List<String> exclusions = new List<String>();
|
|
||||||
foreach(string entry in ReadExclusionRules()) {
|
|
||||||
if(ForceRead || entry.Equals(ExclusionBlock)) {
|
|
||||||
exclusions.Add(entry);
|
|
||||||
ForceRead = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exclusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadExclusionRules();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes the exclusion rules file with a given string list
|
|
||||||
private bool WriteExclusionRules(List<String> lines) {
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (exlude_rules_file_path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
foreach(string line in lines) {
|
|
||||||
writer.WriteLine(line.TrimEnd());
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Writing into exclusion file failed: " + e.Message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if(writer != null) {
|
|
||||||
writer.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes unneeded objects
|
// Removes unneeded objects
|
||||||
private void CollectGarbage ()
|
/* private void CollectGarbage ()
|
||||||
{
|
{
|
||||||
SparkleGit git = new SparkleGit (LocalPath, "gc");
|
SparkleGit git = new SparkleGit (LocalPath, "gc");
|
||||||
git.Start ();
|
git.Start ();
|
||||||
git.WaitForExit ();
|
git.WaitForExit ();
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Garbage collected.");
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Garbage collected.");
|
||||||
}
|
} */
|
||||||
|
|
||||||
|
|
||||||
// Commits the made changes
|
// Commits the made changes
|
||||||
|
@ -486,11 +457,6 @@ namespace SparkleLib {
|
||||||
string output = git_status.StandardOutput.ReadToEnd ().TrimEnd ();
|
string output = git_status.StandardOutput.ReadToEnd ().TrimEnd ();
|
||||||
git_status.WaitForExit ();
|
git_status.WaitForExit ();
|
||||||
|
|
||||||
if (String.IsNullOrEmpty (output)) {
|
|
||||||
// no conflict any more.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string [] lines = output.Split ("\n".ToCharArray ());
|
string [] lines = output.Split ("\n".ToCharArray ());
|
||||||
|
|
||||||
foreach (string line in lines) {
|
foreach (string line in lines) {
|
||||||
|
@ -571,13 +537,10 @@ namespace SparkleLib {
|
||||||
|
|
||||||
List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
|
List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
|
||||||
|
|
||||||
SparkleGit git_log = new SparkleGit (LocalPath, "log -" + count + " --raw -M --date=iso");
|
// Console.InputEncoding = System.Text.Encoding.Unicode;
|
||||||
if ((SparkleBackend.Platform == PlatformID.Unix ||
|
|
||||||
SparkleBackend.Platform == PlatformID.MacOSX)) {
|
|
||||||
// this causes an IOException on windows
|
|
||||||
Console.OutputEncoding = System.Text.Encoding.Unicode;
|
Console.OutputEncoding = System.Text.Encoding.Unicode;
|
||||||
}
|
|
||||||
|
|
||||||
|
SparkleGit git_log = new SparkleGit (LocalPath, "log -" + count + " --raw -M --date=iso");
|
||||||
git_log.Start ();
|
git_log.Start ();
|
||||||
|
|
||||||
// Reading the standard output HAS to go before
|
// Reading the standard output HAS to go before
|
||||||
|
@ -709,9 +672,13 @@ namespace SparkleLib {
|
||||||
FillEmptyDirectories (child_path);
|
FillEmptyDirectories (child_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.GetFiles (path).Length == 0 && !path.Equals (LocalPath))
|
if (Directory.GetFiles (path).Length == 0 &&
|
||||||
|
Directory.GetDirectories (path).Length == 0 &&
|
||||||
|
!path.Equals (LocalPath)) {
|
||||||
|
|
||||||
File.Create (Path.Combine (path, ".empty")).Close ();
|
File.Create (Path.Combine (path, ".empty")).Close ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Creates a pretty commit message based on what has changed
|
// Creates a pretty commit message based on what has changed
|
||||||
|
@ -752,6 +719,10 @@ namespace SparkleLib {
|
||||||
|
|
||||||
foreach (string added in Added) {
|
foreach (string added in Added) {
|
||||||
file_name = added.Trim ("\"".ToCharArray ());
|
file_name = added.Trim ("\"".ToCharArray ());
|
||||||
|
|
||||||
|
if (file_name.EndsWith (".empty"))
|
||||||
|
file_name = file_name.Substring (0, file_name.Length - 6);
|
||||||
|
|
||||||
message += "+ ‘" + file_name + "’" + n;
|
message += "+ ‘" + file_name + "’" + n;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -761,6 +732,10 @@ namespace SparkleLib {
|
||||||
|
|
||||||
foreach (string modified in Modified) {
|
foreach (string modified in Modified) {
|
||||||
file_name = modified.Trim ("\"".ToCharArray ());
|
file_name = modified.Trim ("\"".ToCharArray ());
|
||||||
|
|
||||||
|
if (file_name.EndsWith (".empty"))
|
||||||
|
file_name = file_name.Substring (0, file_name.Length - 6);
|
||||||
|
|
||||||
message += "/ ‘" + file_name + "’" + n;
|
message += "/ ‘" + file_name + "’" + n;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -770,6 +745,10 @@ namespace SparkleLib {
|
||||||
|
|
||||||
foreach (string removed in Removed) {
|
foreach (string removed in Removed) {
|
||||||
file_name = removed.Trim ("\"".ToCharArray ());
|
file_name = removed.Trim ("\"".ToCharArray ());
|
||||||
|
|
||||||
|
if (file_name.EndsWith (".empty"))
|
||||||
|
file_name = file_name.Substring (0, file_name.Length - 6);
|
||||||
|
|
||||||
message += "- ‘" + file_name + "’" + n;
|
message += "- ‘" + file_name + "’" + n;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
@ -796,5 +775,38 @@ namespace SparkleLib {
|
||||||
base.CreateInitialChangeSet ();
|
base.CreateInitialChangeSet ();
|
||||||
SyncUp ();
|
SyncUp ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Recursively gets a folder's size in bytes
|
||||||
|
public override double CalculateSize (DirectoryInfo parent)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists (parent.ToString ()))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
double size = 0;
|
||||||
|
|
||||||
|
// Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
|
||||||
|
// crashes when files are being queried whilst the files have already been deleted.
|
||||||
|
if (parent.Name.Equals ("rebase-apply") ||
|
||||||
|
parent.Name.Equals (".tmp"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
foreach (FileInfo file in parent.GetFiles()) {
|
||||||
|
if (!file.Exists)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size += file.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
||||||
|
size += CalculateSize (directory);
|
||||||
|
|
||||||
|
} catch (Exception) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,172 +0,0 @@
|
||||||
// SparkleShare, a collaboration and sharing tool.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Xml;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
|
||||||
|
|
||||||
// Sets up a fetcher that can get remote folders
|
|
||||||
public class SparkleFetcherHg : SparkleFetcherBase {
|
|
||||||
|
|
||||||
public SparkleFetcherHg (string server, string remote_folder, string target_folder) :
|
|
||||||
base (server, remote_folder, target_folder) { }
|
|
||||||
|
|
||||||
|
|
||||||
public override bool Fetch ()
|
|
||||||
{
|
|
||||||
SparkleHg hg = new SparkleHg (SparklePaths.SparkleTmpPath,
|
|
||||||
"clone \"" + base.remote_url + "\" " + "\"" + base.target_folder + "\"");
|
|
||||||
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Hg", "Exit code " + hg.ExitCode.ToString ());
|
|
||||||
|
|
||||||
if (hg.ExitCode != 0) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
InstallConfiguration ();
|
|
||||||
InstallExcludeRules ();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Install the user's name and email and some config into
|
|
||||||
// the newly cloned repository
|
|
||||||
private void InstallConfiguration ()
|
|
||||||
{
|
|
||||||
string global_config_file_path = Path.Combine (SparklePaths.SparkleConfigPath, "config.xml");
|
|
||||||
|
|
||||||
if (!File.Exists (global_config_file_path))
|
|
||||||
return;
|
|
||||||
|
|
||||||
string repo_config_file_path = SparkleHelpers.CombineMore (base.target_folder, ".hg", "hgrc");
|
|
||||||
string config = String.Join (Environment.NewLine, File.ReadAllLines (repo_config_file_path));
|
|
||||||
|
|
||||||
// Add user info
|
|
||||||
string n = Environment.NewLine;
|
|
||||||
XmlDocument xml = new XmlDocument();
|
|
||||||
xml.Load (global_config_file_path);
|
|
||||||
|
|
||||||
XmlNode node_name = xml.SelectSingleNode ("//user/name/text()");
|
|
||||||
XmlNode node_email = xml.SelectSingleNode ("//user/email/text()");
|
|
||||||
|
|
||||||
// TODO this ignore duplicate names (FolderName (2))
|
|
||||||
string ignore_file_path = base.target_folder.Replace (SparklePaths.SparkleTmpPath,
|
|
||||||
SparklePaths.SparklePath);
|
|
||||||
|
|
||||||
ignore_file_path = SparkleHelpers.CombineMore (ignore_file_path, ".hg", "hgignore");
|
|
||||||
|
|
||||||
config += n +
|
|
||||||
"[ui]" + n +
|
|
||||||
"username = " + node_name.Value + " <" + node_email.Value + ">" + n +
|
|
||||||
"ignore = " + ignore_file_path + n;
|
|
||||||
|
|
||||||
// Write the config to the file
|
|
||||||
TextWriter writer = new StreamWriter (repo_config_file_path);
|
|
||||||
writer.WriteLine (config);
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
string style_file_path = SparkleHelpers.CombineMore (base.target_folder, ".hg", "log.style");
|
|
||||||
|
|
||||||
string style = "changeset = \"{file_mods}{file_adds}{file_dels}\"" + n +
|
|
||||||
"file_add = \"A {file_add}\\n\"" + n +
|
|
||||||
"file_mod = \"M {file_mod}\\n\"" + n +
|
|
||||||
"file_del = \"D {file_del}\\n\"" + n;
|
|
||||||
|
|
||||||
writer = new StreamWriter (style_file_path);
|
|
||||||
writer.WriteLine (style);
|
|
||||||
writer.Close ();
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Added configuration to '" + repo_config_file_path + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Add a .gitignore file to the repo
|
|
||||||
private void InstallExcludeRules ()
|
|
||||||
{
|
|
||||||
string exlude_rules_file_path = SparkleHelpers.CombineMore (
|
|
||||||
this.target_folder, ".hg", "hgignore");
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (exlude_rules_file_path);
|
|
||||||
|
|
||||||
writer.WriteLine ("syntax: glob");
|
|
||||||
|
|
||||||
// gedit and emacs
|
|
||||||
writer.WriteLine ("*~");
|
|
||||||
|
|
||||||
// vi(m)
|
|
||||||
writer.WriteLine (".*.sw[a-z]");
|
|
||||||
writer.WriteLine ("*.un~");
|
|
||||||
writer.WriteLine ("*.swp");
|
|
||||||
writer.WriteLine ("*.swo");
|
|
||||||
|
|
||||||
// KDE
|
|
||||||
writer.WriteLine (".directory");
|
|
||||||
|
|
||||||
// Mac OSX
|
|
||||||
writer.WriteLine (".DS_Store");
|
|
||||||
writer.WriteLine ("Icon?");
|
|
||||||
writer.WriteLine ("._*");
|
|
||||||
writer.WriteLine (".Spotlight-V100");
|
|
||||||
writer.WriteLine (".Trashes");
|
|
||||||
|
|
||||||
// Mac OSX
|
|
||||||
writer.WriteLine ("*(Autosaved).graffle");
|
|
||||||
|
|
||||||
// Windows
|
|
||||||
writer.WriteLine ("Thumbs.db");
|
|
||||||
writer.WriteLine ("Desktop.ini");
|
|
||||||
|
|
||||||
// CVS
|
|
||||||
writer.WriteLine ("*/CVS/*");
|
|
||||||
writer.WriteLine (".cvsignore");
|
|
||||||
writer.WriteLine ("*/.cvsignore");
|
|
||||||
|
|
||||||
// Subversion
|
|
||||||
writer.WriteLine ("/.svn/*");
|
|
||||||
writer.WriteLine ("*/.svn/*");
|
|
||||||
|
|
||||||
writer.Close ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class SparkleHg : Process {
|
|
||||||
|
|
||||||
public SparkleHg (string path, string args) : base ()
|
|
||||||
{
|
|
||||||
EnableRaisingEvents = true;
|
|
||||||
StartInfo.FileName = "/opt/local/bin/hg";
|
|
||||||
StartInfo.Arguments = args;
|
|
||||||
StartInfo.RedirectStandardOutput = true;
|
|
||||||
StartInfo.UseShellExecute = false;
|
|
||||||
StartInfo.WorkingDirectory = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
new public void Start ()
|
|
||||||
{
|
|
||||||
SparkleHelpers.DebugInfo ("Cmd", StartInfo.FileName + " " + StartInfo.Arguments);
|
|
||||||
base.Start ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,487 +0,0 @@
|
||||||
// SparkleShare, a collaboration and sharing tool.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
|
||||||
|
|
||||||
public class SparkleRepoHg : SparkleRepoBase {
|
|
||||||
|
|
||||||
private string exlude_rules_file_path;
|
|
||||||
private string ExclusionBlock = "#Temporary Exclusions";
|
|
||||||
|
|
||||||
public SparkleRepoHg (string path, SparkleBackend backend) :
|
|
||||||
base (path, backend) {
|
|
||||||
// Set exclude file path
|
|
||||||
exlude_rules_file_path = SparkleHelpers.CombineMore (
|
|
||||||
LocalPath, ".hg", "hgignore");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override string Identifier {
|
|
||||||
get {
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "log -r : --limit 1 --template \"{node}\"");
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
return hg.StandardOutput.ReadToEnd ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override string CurrentRevision {
|
|
||||||
get {
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "log --limit 1 --template \"{node}\"");
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
string hash = hg.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
if (hash.Length > 0)
|
|
||||||
return hash;
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool CheckForRemoteChanges ()
|
|
||||||
{
|
|
||||||
return true; // Mercurial doesn't have a way to check for the remote hash
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool SyncUp ()
|
|
||||||
{
|
|
||||||
Add ();
|
|
||||||
|
|
||||||
string message = FormatCommitMessage ();
|
|
||||||
Commit (message);
|
|
||||||
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "push");
|
|
||||||
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
if (hg.ExitCode == 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool SyncDown ()
|
|
||||||
{
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "pull");
|
|
||||||
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
if (hg.ExitCode == 0) {
|
|
||||||
Merge ();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool AnyDifferences {
|
|
||||||
get {
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "status");
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
string output = hg.StandardOutput.ReadToEnd ().TrimEnd ();
|
|
||||||
string [] lines = output.Split ("\n".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string line in lines) {
|
|
||||||
if (line.Length > 1 && !line [1].Equals (" "))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool HasUnsyncedChanges {
|
|
||||||
get {
|
|
||||||
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
|
|
||||||
".hg", "has_unsynced_changes");
|
|
||||||
|
|
||||||
return File.Exists (unsynced_file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
set {
|
|
||||||
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath,
|
|
||||||
".hg", "has_unsynced_changes");
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
if (!File.Exists (unsynced_file_path))
|
|
||||||
File.Create (unsynced_file_path).Close ();
|
|
||||||
} else {
|
|
||||||
File.Delete (unsynced_file_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Stages the made changes
|
|
||||||
private void Add ()
|
|
||||||
{
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "addremove --quiet");
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Hg", "[" + Name + "] Changes staged");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new file to be ignored
|
|
||||||
public override bool AddExclusionRule (FileSystemEventArgs args) {
|
|
||||||
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
exclusions = ReadExclusionRules();
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the local exclusions section
|
|
||||||
bool added = false;
|
|
||||||
for(int i = 0; i < exclusions.Count; i++) {
|
|
||||||
string entry = exclusions[i];
|
|
||||||
if(entry.Equals(ExclusionBlock)) {
|
|
||||||
// add a new exclusion rule containing a file path
|
|
||||||
exclusions.Insert(i + 1, RelativePath);
|
|
||||||
added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For compability to existing repos:
|
|
||||||
* Add a "#Temporary Exclusions"-Block to the
|
|
||||||
* ignore file in order to recognize this
|
|
||||||
* exclude rules later on
|
|
||||||
*/
|
|
||||||
if(!added) {
|
|
||||||
exclusions.Add(ExclusionBlock);
|
|
||||||
exclusions.Add(RelativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write exceptions list back to file
|
|
||||||
return WriteExclusionRules(exclusions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether a specific rule exists in the exclusion file
|
|
||||||
public override bool ExclusionRuleExists(FileSystemEventArgs args) {
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
// Read rules from temporary block only
|
|
||||||
exclusions = ReadExclusionRules(true);
|
|
||||||
|
|
||||||
foreach(string entry in exclusions) {
|
|
||||||
if(entry.Equals(RelativePath)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Cannot determine whether an exclusion rule for " +
|
|
||||||
args.FullPath + " already exists or not.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove file from exclusion list when they are readable again
|
|
||||||
public override bool RemoveExclusionRule(FileSystemEventArgs args) {
|
|
||||||
string RelativePath = SparkleHelpers.DiffPaths(args.FullPath, LocalPath);
|
|
||||||
|
|
||||||
List<String> exclusions;
|
|
||||||
try {
|
|
||||||
exclusions = ReadExclusionRules();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Removing a rule should only apply to rules in the "Temporary Exclusion"-block.
|
|
||||||
* Therefore we first read until reaching the block and then remove the rule.
|
|
||||||
*
|
|
||||||
* We cannot use ReadExclusionRules(true) here since we write all lines back
|
|
||||||
* to the file. This would result in a crippled exclusion file.
|
|
||||||
*/
|
|
||||||
bool BlockReached = false;
|
|
||||||
foreach(string entry in exclusions) {
|
|
||||||
if(entry.Equals(ExclusionBlock)) {
|
|
||||||
BlockReached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove this rule
|
|
||||||
if(BlockReached && entry.Equals(RelativePath)) {
|
|
||||||
exclusions.Remove(entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteExclusionRules(exclusions);
|
|
||||||
} catch {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Unable to remove exclusion rule for entry " + RelativePath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads the exclusion rules file into a string list
|
|
||||||
private List<String> ReadExclusionRules() {
|
|
||||||
|
|
||||||
List<String> exclusions = new List<String>();
|
|
||||||
TextReader reader = new StreamReader (exlude_rules_file_path);;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while(reader.Peek() > -1) {
|
|
||||||
exclusions.Add(reader.ReadLine().TrimEnd());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Reading from exclusion file failed: " + e.Message);
|
|
||||||
return new List<String>();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if(reader != null) {
|
|
||||||
reader.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exclusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads rules only from temporary exclusion block
|
|
||||||
private List<String> ReadExclusionRules(bool TempOnly) {
|
|
||||||
if(TempOnly) {
|
|
||||||
bool ForceRead = false;
|
|
||||||
List<String> exclusions = new List<String>();
|
|
||||||
foreach(string entry in ReadExclusionRules()) {
|
|
||||||
if(ForceRead || entry.Equals(ExclusionBlock)) {
|
|
||||||
exclusions.Add(entry);
|
|
||||||
ForceRead = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exclusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadExclusionRules();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes the exclusion rules file with a given string list
|
|
||||||
private bool WriteExclusionRules(List<String> lines) {
|
|
||||||
|
|
||||||
TextWriter writer = new StreamWriter (exlude_rules_file_path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
foreach(string line in lines) {
|
|
||||||
writer.WriteLine(line.TrimEnd());
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
SparkleHelpers.DebugInfo("Error", "Writing into exclusion file failed: " + e.Message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if(writer != null) {
|
|
||||||
writer.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commits the made changes
|
|
||||||
private void Commit (string message)
|
|
||||||
{
|
|
||||||
if (!AnyDifferences)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "commit -m '" + message + "'");
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Merges the fetched changes
|
|
||||||
private void Merge ()
|
|
||||||
{
|
|
||||||
DisableWatching ();
|
|
||||||
|
|
||||||
if (AnyDifferences) {
|
|
||||||
Add ();
|
|
||||||
|
|
||||||
string commit_message = FormatCommitMessage ();
|
|
||||||
Commit (commit_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
SparkleHg hg = new SparkleHg (LocalPath, "update");
|
|
||||||
|
|
||||||
hg.Start ();
|
|
||||||
hg.WaitForExit ();
|
|
||||||
|
|
||||||
EnableWatching ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns a list of the latest change sets
|
|
||||||
public override List<SparkleChangeSet> GetChangeSets (int count)
|
|
||||||
{
|
|
||||||
if (count < 1)
|
|
||||||
count = 30;
|
|
||||||
|
|
||||||
List <SparkleChangeSet> change_sets = new List <SparkleChangeSet> ();
|
|
||||||
|
|
||||||
SparkleHg hg_log = new SparkleHg (LocalPath, "log --limit " + count + " --style changelog --verbose --stat");
|
|
||||||
Console.OutputEncoding = System.Text.Encoding.Unicode;
|
|
||||||
hg_log.Start ();
|
|
||||||
|
|
||||||
// Reading the standard output HAS to go before
|
|
||||||
// WaitForExit, or it will hang forever on output > 4096 bytes
|
|
||||||
string output = hg_log.StandardOutput.ReadToEnd ();
|
|
||||||
hg_log.WaitForExit ();
|
|
||||||
|
|
||||||
string [] lines = output.Split ("\n".ToCharArray ());
|
|
||||||
List <string> entries = new List <string> ();
|
|
||||||
|
|
||||||
int j = 0;
|
|
||||||
string entry = "", last_entry = "";
|
|
||||||
foreach (string line in lines) {
|
|
||||||
if (line.StartsWith ("2") && line.EndsWith (")") && j > 0) {
|
|
||||||
entries.Add (entry);
|
|
||||||
entry = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
entry += line + "\n";
|
|
||||||
j++;
|
|
||||||
|
|
||||||
last_entry = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.Add (last_entry);
|
|
||||||
|
|
||||||
Regex regex = new Regex (@"([0-9]{4})-([0-9]{2})-([0-9]{2}).*([0-9]{2}):([0-9]{2}).*.([0-9]{4})" +
|
|
||||||
"(.+)<(.+)>.*.([a-z0-9]{12})", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
foreach (string log_entry in entries) {
|
|
||||||
|
|
||||||
bool is_merge_commit = false;
|
|
||||||
|
|
||||||
Match match = regex.Match (log_entry);
|
|
||||||
|
|
||||||
if (!match.Success)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SparkleChangeSet change_set = new SparkleChangeSet () {
|
|
||||||
Revision = match.Groups [9].Value,
|
|
||||||
IsMagical = is_merge_commit
|
|
||||||
};
|
|
||||||
|
|
||||||
change_set.User.Name = match.Groups [7].Value.Trim ();
|
|
||||||
change_set.User.Email = match.Groups [8].Value;
|
|
||||||
|
|
||||||
|
|
||||||
change_set.Timestamp = new DateTime (int.Parse (match.Groups [1].Value),
|
|
||||||
int.Parse (match.Groups [2].Value), int.Parse (match.Groups [3].Value),
|
|
||||||
int.Parse (match.Groups [4].Value), int.Parse (match.Groups [5].Value), 0);
|
|
||||||
|
|
||||||
string [] entry_lines = log_entry.Split ("\n".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string entry_line in entry_lines) {
|
|
||||||
if (!entry_line.StartsWith ("\t* "))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (entry_line.EndsWith ("new file.")) {
|
|
||||||
string files = entry_line.Substring (3, entry_line.Length - 13);
|
|
||||||
string [] added_files = files.Split (",".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string added_file in added_files) {
|
|
||||||
string file = added_file.TrimEnd (": ".ToCharArray ());
|
|
||||||
change_set.Added.Add (file);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (entry_line.EndsWith ("deleted file.")) {
|
|
||||||
string files = entry_line.Substring (3, entry_line.Length - 17);
|
|
||||||
string [] deleted_files = files.Split (",".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string deleted_file in deleted_files) {
|
|
||||||
string file = deleted_file.TrimEnd (": ".ToCharArray ());
|
|
||||||
change_set.Deleted.Add (file);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (!"".Equals (entry_line.Trim ())){
|
|
||||||
string files = entry_line.Substring (3);
|
|
||||||
files = files.TrimEnd (":".ToCharArray());
|
|
||||||
string [] edited_files = files.Split (",".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string edited_file in edited_files) {
|
|
||||||
if (!change_set.Added.Contains (edited_file) &&
|
|
||||||
!change_set.Deleted.Contains (edited_file)) {
|
|
||||||
|
|
||||||
change_set.Edited.Add (edited_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
change_sets.Add (change_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
return change_sets;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates a pretty commit message based on what has changed
|
|
||||||
private string FormatCommitMessage () // TODO
|
|
||||||
{
|
|
||||||
return "SparkleShare Hg";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void CreateInitialChangeSet ()
|
|
||||||
{
|
|
||||||
base.CreateInitialChangeSet ();
|
|
||||||
Add ();
|
|
||||||
|
|
||||||
string message = FormatCommitMessage ();
|
|
||||||
Commit (message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool UsesNotificationCenter
|
|
||||||
{
|
|
||||||
get {
|
|
||||||
string file_path = SparkleHelpers.CombineMore (LocalPath, ".hg", "disable_notification_center");
|
|
||||||
return !File.Exists (file_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +1,6 @@
|
||||||
ASSEMBLY = SparkleLib
|
ASSEMBLY = SparkleLib
|
||||||
TARGET = library
|
TARGET = library
|
||||||
|
|
||||||
if HAVE_SMARTIRC4NET
|
|
||||||
LINK = $(REF_SPARKLELIB) $(LINK_SMARTIRC4NET_SYSTEM)
|
|
||||||
else
|
|
||||||
LINK = $(REF_SPARKLELIB) $(LINK_SMARTIRC4NET_LOCAL)
|
|
||||||
endif
|
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
Defines.cs \
|
Defines.cs \
|
||||||
Git/SparkleFetcherGit.cs \
|
Git/SparkleFetcherGit.cs \
|
||||||
|
@ -17,17 +11,11 @@ SOURCES = \
|
||||||
SparkleFetcherBase.cs \
|
SparkleFetcherBase.cs \
|
||||||
SparkleHelpers.cs \
|
SparkleHelpers.cs \
|
||||||
SparkleListenerBase.cs \
|
SparkleListenerBase.cs \
|
||||||
SparkleListenerIrc.cs \
|
|
||||||
SparkleListenerTcp.cs \
|
SparkleListenerTcp.cs \
|
||||||
SparkleOptions.cs \
|
|
||||||
SparkleRepoBase.cs \
|
SparkleRepoBase.cs \
|
||||||
SparkleWatcher.cs
|
SparkleWatcher.cs
|
||||||
|
|
||||||
|
|
||||||
SMARTIRC4NET_FILES_EXPANDED = $(foreach file, $(SMARTIRC4NET_FILES), $(top_builddir)/$(file))
|
|
||||||
|
|
||||||
EXTRA_BUNDLE = $(SMARTIRC4NET_FILES_EXPANDED)
|
|
||||||
|
|
||||||
install-data-hook:
|
install-data-hook:
|
||||||
for ASM in $(EXTRA_BUNDLE); do \
|
for ASM in $(EXTRA_BUNDLE); do \
|
||||||
$(INSTALL) -m 0755 $$ASM $(DESTDIR)$(moduledir); \
|
$(INSTALL) -m 0755 $$ASM $(DESTDIR)$(moduledir); \
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace SparkleLib {
|
||||||
public class SparkleFolder {
|
public class SparkleFolder {
|
||||||
|
|
||||||
public string Name;
|
public string Name;
|
||||||
// TODO: Uri
|
public Uri RemoteAddress;
|
||||||
|
|
||||||
public string FullPath {
|
public string FullPath {
|
||||||
get {
|
get {
|
||||||
|
|
|
@ -19,10 +19,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Security.Principal;
|
||||||
#if __MonoCS__
|
|
||||||
using Mono.Unix;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
@ -33,12 +30,14 @@ namespace SparkleLib {
|
||||||
"sparkleshare");
|
"sparkleshare");
|
||||||
|
|
||||||
public static SparkleConfig DefaultConfig = new SparkleConfig (ConfigPath, "config.xml");
|
public static SparkleConfig DefaultConfig = new SparkleConfig (ConfigPath, "config.xml");
|
||||||
|
|
||||||
|
|
||||||
public string FullPath;
|
public string FullPath;
|
||||||
|
|
||||||
public string HomePath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
|
public string HomePath {
|
||||||
public string TmpPath;
|
get {
|
||||||
|
return Environment.GetFolderPath (Environment.SpecialFolder.Personal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public string FoldersPath {
|
public string FoldersPath {
|
||||||
get {
|
get {
|
||||||
|
@ -49,11 +48,16 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string TmpPath {
|
||||||
|
get {
|
||||||
|
return Path.Combine (FoldersPath, ".tmp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public SparkleConfig (string config_path, string config_file_name)
|
public SparkleConfig (string config_path, string config_file_name)
|
||||||
{
|
{
|
||||||
FullPath = System.IO.Path.Combine (config_path, config_file_name);
|
FullPath = System.IO.Path.Combine (config_path, config_file_name);
|
||||||
TmpPath = Path.Combine (FoldersPath, ".tmp");
|
|
||||||
|
|
||||||
if (!Directory.Exists (config_path)) {
|
if (!Directory.Exists (config_path)) {
|
||||||
Directory.CreateDirectory (config_path);
|
Directory.CreateDirectory (config_path);
|
||||||
|
@ -99,13 +103,13 @@ namespace SparkleLib {
|
||||||
|
|
||||||
if (SparkleBackend.Platform == PlatformID.Unix ||
|
if (SparkleBackend.Platform == PlatformID.Unix ||
|
||||||
SparkleBackend.Platform == PlatformID.MacOSX) {
|
SparkleBackend.Platform == PlatformID.MacOSX) {
|
||||||
#if __MonoCS__
|
|
||||||
user_name = new UnixUserInfo (UnixEnvironment.UserName).RealName;
|
user_name = Environment.UserName;
|
||||||
if (string.IsNullOrEmpty (user_name))
|
if (string.IsNullOrEmpty (user_name))
|
||||||
user_name = UnixEnvironment.UserName;
|
user_name = "";
|
||||||
else
|
else
|
||||||
user_name = user_name.TrimEnd (",".ToCharArray ());
|
user_name = user_name.TrimEnd (",".ToCharArray ());
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
user_name = Environment.UserName;
|
user_name = Environment.UserName;
|
||||||
}
|
}
|
||||||
|
@ -148,10 +152,59 @@ namespace SparkleLib {
|
||||||
email_node.InnerText = user.Email;
|
email_node.InnerText = user.Email;
|
||||||
|
|
||||||
this.Save ();
|
this.Save ();
|
||||||
|
|
||||||
|
ConfigureSSH ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ConfigureSSH ()
|
||||||
|
{
|
||||||
|
if (User.Email.Equals ("Unknown"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
|
||||||
|
|
||||||
|
if (!(SparkleBackend.Platform == PlatformID.Unix ||
|
||||||
|
SparkleBackend.Platform == PlatformID.MacOSX)) {
|
||||||
|
|
||||||
|
path = Environment.ExpandEnvironmentVariables ("%HOMEDRIVE%%HOMEPATH%");
|
||||||
|
}
|
||||||
|
|
||||||
|
string ssh_config_path = Path.Combine (path, ".ssh");
|
||||||
|
string ssh_config_file_path = SparkleHelpers.CombineMore (path, ".ssh", "config");
|
||||||
|
string ssh_config = "IdentityFile " +
|
||||||
|
Path.Combine (SparkleConfig.ConfigPath, "sparkleshare." + User.Email + ".key");
|
||||||
|
|
||||||
|
if (!Directory.Exists (ssh_config_path))
|
||||||
|
Directory.CreateDirectory (ssh_config_path);
|
||||||
|
|
||||||
|
if (File.Exists (ssh_config_file_path)) {
|
||||||
|
string current_config = File.ReadAllText (ssh_config_file_path);
|
||||||
|
if (current_config.Contains (ssh_config))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (current_config.EndsWith ("\n\n"))
|
||||||
|
ssh_config = "# SparkleShare's key\n" + ssh_config;
|
||||||
|
else if (current_config.EndsWith ("\n"))
|
||||||
|
ssh_config = "\n# SparkleShare's key\n" + ssh_config;
|
||||||
|
else
|
||||||
|
ssh_config = "\n\n# SparkleShare's key\n" + ssh_config;
|
||||||
|
|
||||||
|
TextWriter writer = File.AppendText (ssh_config_file_path);
|
||||||
|
writer.Write (ssh_config + "\n");
|
||||||
|
writer.Close ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
File.WriteAllText (ssh_config_file_path, ssh_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chmod644 (ssh_config_file_path);
|
||||||
|
|
||||||
|
SparkleHelpers.DebugInfo ("Config", "Added key to " + ssh_config_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<string> Folders {
|
public List<string> Folders {
|
||||||
get {
|
get {
|
||||||
List<string> folders = new List<string> ();
|
List<string> folders = new List<string> ();
|
||||||
|
@ -348,6 +401,16 @@ namespace SparkleLib {
|
||||||
this.Save (FullPath);
|
this.Save (FullPath);
|
||||||
SparkleHelpers.DebugInfo ("Config", "Updated \"" + FullPath + "\"");
|
SparkleHelpers.DebugInfo ("Config", "Updated \"" + FullPath + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Chmod644 (string file_path)
|
||||||
|
{
|
||||||
|
// Hack to be able to set the permissions on a file
|
||||||
|
// that OpenSSH still likes without resorting to Mono.Unix
|
||||||
|
FileInfo file_info = new FileInfo (file_path);
|
||||||
|
file_info.Attributes = FileAttributes.ReadOnly;
|
||||||
|
file_info.Attributes = FileAttributes.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,17 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Security.AccessControl;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
#if __MonoCS__
|
|
||||||
using Mono.Unix;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
// Sets up a fetcher that can get remote folders
|
// Sets up a fetcher that can get remote folders
|
||||||
public abstract class SparkleFetcherBase {
|
public abstract class SparkleFetcherBase {
|
||||||
|
|
||||||
public delegate void StartedEventHandler ();
|
public delegate void StartedEventHandler ();
|
||||||
public delegate void FinishedEventHandler ();
|
public delegate void FinishedEventHandler (string [] warnings);
|
||||||
public delegate void FailedEventHandler ();
|
public delegate void FailedEventHandler ();
|
||||||
public delegate void ProgressChangedEventHandler (double percentage);
|
public delegate void ProgressChangedEventHandler (double percentage);
|
||||||
|
|
||||||
|
@ -54,7 +51,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
|
|
||||||
public abstract bool Fetch ();
|
public abstract bool Fetch ();
|
||||||
|
public abstract string [] Warnings { get; }
|
||||||
|
|
||||||
// Clones the remote repository
|
// Clones the remote repository
|
||||||
public void Start ()
|
public void Start ()
|
||||||
|
@ -85,7 +82,7 @@ namespace SparkleLib {
|
||||||
EnableHostKeyCheckingForHost (host);
|
EnableHostKeyCheckingForHost (host);
|
||||||
|
|
||||||
if (Finished != null)
|
if (Finished != null)
|
||||||
Finished ();
|
Finished (Warnings);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
SparkleHelpers.DebugInfo ("Fetcher", "Failed");
|
SparkleHelpers.DebugInfo ("Fetcher", "Failed");
|
||||||
|
@ -159,13 +156,8 @@ namespace SparkleLib {
|
||||||
File.WriteAllText (ssh_config_file_path, ssh_config);
|
File.WriteAllText (ssh_config_file_path, ssh_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __MonoCS__
|
Chmod644 (ssh_config_file_path);
|
||||||
UnixFileSystemInfo file_info = new UnixFileInfo (ssh_config_file_path);
|
SparkleHelpers.DebugInfo ("Fetcher", "Disabled host key checking for " + host);
|
||||||
file_info.FileAccessPermissions = (FileAccessPermissions.UserRead |
|
|
||||||
FileAccessPermissions.UserWrite);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Fetcher", "Disabled host key checking " + host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,8 +165,8 @@ namespace SparkleLib {
|
||||||
{
|
{
|
||||||
string path = SparkleConfig.DefaultConfig.HomePath;
|
string path = SparkleConfig.DefaultConfig.HomePath;
|
||||||
|
|
||||||
if (!(SparkleBackend.Platform == PlatformID.Unix ||
|
if (SparkleBackend.Platform != PlatformID.Unix &&
|
||||||
SparkleBackend.Platform == PlatformID.MacOSX)) {
|
SparkleBackend.Platform != PlatformID.MacOSX) {
|
||||||
|
|
||||||
path = Environment.ExpandEnvironmentVariables ("%HOMEDRIVE%%HOMEPATH%");
|
path = Environment.ExpandEnvironmentVariables ("%HOMEDRIVE%%HOMEPATH%");
|
||||||
}
|
}
|
||||||
|
@ -211,12 +203,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
File.WriteAllText (ssh_config_file_path, new_ssh_config.Trim ());
|
File.WriteAllText (ssh_config_file_path, new_ssh_config.Trim ());
|
||||||
|
Chmod644 (ssh_config_file_path);
|
||||||
#if __MonoCS__
|
|
||||||
UnixFileSystemInfo file_info = new UnixFileInfo (ssh_config_file_path);
|
|
||||||
file_info.FileAccessPermissions = (FileAccessPermissions.UserRead |
|
|
||||||
FileAccessPermissions.UserWrite);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,5 +221,15 @@ namespace SparkleLib {
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Chmod644 (string file_path)
|
||||||
|
{
|
||||||
|
// Hack to be able to set the permissions on a file
|
||||||
|
// that OpenSSH still likes without resorting to Mono.Unix
|
||||||
|
FileInfo file_info = new FileInfo (file_path);
|
||||||
|
file_info.Attributes = FileAttributes.ReadOnly;
|
||||||
|
file_info.Attributes = FileAttributes.Normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="Mono.Posix" />
|
<Reference Include="Mono.Posix" />
|
||||||
<Reference Include="Meebey.SmartIrc4net, Version=0.4.5.0, Culture=neutral, PublicKeyToken=7868485fbf407e0f">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\bin\Meebey.SmartIrc4net.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="SparkleRepoBase.cs" />
|
<Compile Include="SparkleRepoBase.cs" />
|
||||||
|
|
|
@ -75,9 +75,6 @@ namespace SparkleLib {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
||||||
break;
|
break;
|
||||||
case "irc":
|
|
||||||
listeners.Add (new SparkleListenerIrc (announce_uri, folder_identifier));
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
listeners.Add (new SparkleListenerTcp (announce_uri, folder_identifier));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
// SparkleShare, a collaboration and sharing tool.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
using Meebey.SmartIrc4net;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
|
||||||
|
|
||||||
public class SparkleListenerIrc : SparkleListenerBase {
|
|
||||||
|
|
||||||
private Thread thread;
|
|
||||||
private IrcClient client;
|
|
||||||
private string nick;
|
|
||||||
private string announcements_password;
|
|
||||||
private bool allow_passwordless_join;
|
|
||||||
|
|
||||||
|
|
||||||
public SparkleListenerIrc (Uri server, string folder_identifier) :
|
|
||||||
base (server, folder_identifier)
|
|
||||||
{
|
|
||||||
// Try to get a uniqueish nickname
|
|
||||||
this.nick = SHA1 (DateTime.Now.ToString ("ffffff") + "sparkles");
|
|
||||||
|
|
||||||
// Most irc servers don't allow nicknames starting
|
|
||||||
// with a number, so prefix an alphabetic character
|
|
||||||
this.nick = "s" + this.nick.Substring (0, 7);
|
|
||||||
|
|
||||||
// Optional password to make the channel access more safe
|
|
||||||
this.announcements_password =
|
|
||||||
SparkleConfig.DefaultConfig.GetConfigOption ("announcements_password");
|
|
||||||
|
|
||||||
// Option to allow access to channel when no password is defined
|
|
||||||
try {
|
|
||||||
string option = SparkleConfig.DefaultConfig.GetConfigOption ("allow_passwordless_join");
|
|
||||||
this.allow_passwordless_join = (option == null || Convert.ToBoolean (option));
|
|
||||||
} catch (Exception) {
|
|
||||||
this.allow_passwordless_join = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.channels.Add ("#" + folder_identifier);
|
|
||||||
|
|
||||||
this.client = new IrcClient () {
|
|
||||||
PingTimeout = 180,
|
|
||||||
PingInterval = 60
|
|
||||||
};
|
|
||||||
|
|
||||||
string proxy = Environment.GetEnvironmentVariable ("http_proxy");
|
|
||||||
Uri proxy_uri = null;
|
|
||||||
if (!String.IsNullOrEmpty (proxy) &&
|
|
||||||
Uri.TryCreate (proxy, UriKind.Absolute, out proxy_uri)) {
|
|
||||||
|
|
||||||
#if __MonoCS__
|
|
||||||
if (proxy_uri.Scheme == "http") {
|
|
||||||
this.client.ProxyType = ProxyType.Http;
|
|
||||||
this.client.ProxyHost = proxy_uri.Host;
|
|
||||||
this.client.ProxyPort = proxy_uri.Port;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.OnConnected += delegate {
|
|
||||||
base.is_connecting = false;
|
|
||||||
OnConnected ();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.client.OnDisconnected += delegate {
|
|
||||||
base.is_connecting = false;
|
|
||||||
OnDisconnected ();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.client.OnError += delegate {
|
|
||||||
base.is_connecting = false;
|
|
||||||
OnDisconnected ();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.client.OnChannelMessage += delegate (object o, IrcEventArgs args) {
|
|
||||||
string message = args.Data.Message.Trim ();
|
|
||||||
string folder_id = args.Data.Channel.Substring (1); // remove the starting hash
|
|
||||||
OnAnnouncement (new SparkleAnnouncement (folder_id, message));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool IsConnected {
|
|
||||||
get {
|
|
||||||
return this.client.IsConnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Starts a new thread and listens to the channel
|
|
||||||
public override void Connect ()
|
|
||||||
{
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Connecting to " + Server);
|
|
||||||
|
|
||||||
base.is_connecting = true;
|
|
||||||
|
|
||||||
this.thread = new Thread (
|
|
||||||
new ThreadStart (delegate {
|
|
||||||
try {
|
|
||||||
// Connect, login, and join the channel
|
|
||||||
int port = base.server.Port;
|
|
||||||
|
|
||||||
if (port < 0)
|
|
||||||
port = 6667;
|
|
||||||
|
|
||||||
this.client.Connect (base.server.Host, port);
|
|
||||||
this.client.Login (this.nick, this.nick, 8, this.nick);
|
|
||||||
|
|
||||||
foreach (string channel in base.channels) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty (this.announcements_password)) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Password set to access the channel");
|
|
||||||
this.client.RfcJoin (channel, this.announcements_password);
|
|
||||||
this.client.RfcMode (channel, "+k " + this.announcements_password);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (this.allow_passwordless_join) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Accessing unprotected channel, change the setting to not access");
|
|
||||||
this.client.RfcJoin (channel);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Unprotected channel, change the setting to access");
|
|
||||||
base.is_connecting = false;
|
|
||||||
OnDisconnected ();
|
|
||||||
throw new ConnectionException ("Unprotected channel, change the setting to access");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.RfcMode (channel, "+s");
|
|
||||||
}
|
|
||||||
|
|
||||||
// List to the channel, this blocks the thread
|
|
||||||
this.client.Listen ();
|
|
||||||
|
|
||||||
// Disconnect when we time out
|
|
||||||
this.client.Disconnect ();
|
|
||||||
|
|
||||||
} catch (ConnectionException e) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Could not connect to " + Server + ": " + e.Message);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.thread.Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void AlsoListenTo (string folder_identifier)
|
|
||||||
{
|
|
||||||
string channel = "#" + folder_identifier;
|
|
||||||
if (!base.channels.Contains (channel)) {
|
|
||||||
base.channels.Add (channel);
|
|
||||||
|
|
||||||
if (IsConnected) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Joining channel " + channel);
|
|
||||||
if (this.announcements_password != null) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Password set to access the channel");
|
|
||||||
this.client.RfcJoin (channel, this.announcements_password);
|
|
||||||
this.client.RfcMode (channel, "+k " + this.announcements_password);
|
|
||||||
} else {
|
|
||||||
if (allow_passwordless_join) {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Accessing a dangerous channel change the setting to not access");
|
|
||||||
this.client.RfcJoin (channel);
|
|
||||||
} else {
|
|
||||||
SparkleHelpers.DebugInfo ("ListenerIrc", "Dangerous channel, change the setting to access");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.client.RfcMode (channel, "+s");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void Announce (SparkleAnnouncement announcement)
|
|
||||||
{
|
|
||||||
string channel = "#" + announcement.FolderIdentifier;
|
|
||||||
this.client.SendMessage (SendType.Message, channel, announcement.Message);
|
|
||||||
|
|
||||||
// Also announce to ourselves for debugging purposes
|
|
||||||
// base.OnAnnouncement (announcement);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void Dispose ()
|
|
||||||
{
|
|
||||||
this.thread.Abort ();
|
|
||||||
this.thread.Join ();
|
|
||||||
base.Dispose ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates a SHA-1 hash of input
|
|
||||||
private string SHA1 (string s)
|
|
||||||
{
|
|
||||||
SHA1 sha1 = new SHA1CryptoServiceProvider ();
|
|
||||||
Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
|
|
||||||
Byte[] encoded_bytes = sha1.ComputeHash (bytes);
|
|
||||||
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
// SparkleShare, a collaboration and sharing tool.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace SparkleLib {
|
|
||||||
|
|
||||||
public static class SparklePaths {
|
|
||||||
|
|
||||||
public static string HomePath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
|
|
||||||
public static string SparklePath = Path.Combine (HomePath ,"SparkleShare");
|
|
||||||
public static string SparkleTmpPath = Path.Combine (SparklePath, ".tmp");
|
|
||||||
public static string SparkleConfigPath = Path.Combine (Environment.GetFolderPath (
|
|
||||||
Environment.SpecialFolder.ApplicationData), "sparkleshare");
|
|
||||||
public static string SparkleLocalIconPath = Path.Combine (SparkleConfigPath, "icons");
|
|
||||||
|
|
||||||
public static string SparkleInstallPath = Path.Combine (Defines.PREFIX, "sparkleshare");
|
|
||||||
public static string SparkleIconPath = SparkleHelpers.CombineMore (Defines.DATAROOTDIR, "sparkleshare", "icons");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ namespace SparkleLib {
|
||||||
private bool has_changed = false;
|
private bool has_changed = false;
|
||||||
private Object change_lock = new Object ();
|
private Object change_lock = new Object ();
|
||||||
private Object watch_lock = new Object ();
|
private Object watch_lock = new Object ();
|
||||||
|
private double progress_percentage = 0.0;
|
||||||
|
private string progress_speed = "";
|
||||||
|
|
||||||
protected SparkleListenerBase listener;
|
protected SparkleListenerBase listener;
|
||||||
protected SyncStatus status;
|
protected SyncStatus status;
|
||||||
|
@ -64,19 +66,23 @@ namespace SparkleLib {
|
||||||
public abstract string CurrentRevision { get; }
|
public abstract string CurrentRevision { get; }
|
||||||
public abstract bool SyncUp ();
|
public abstract bool SyncUp ();
|
||||||
public abstract bool SyncDown ();
|
public abstract bool SyncDown ();
|
||||||
|
public abstract double CalculateSize (DirectoryInfo parent);
|
||||||
public abstract bool HasUnsyncedChanges { get; set; }
|
public abstract bool HasUnsyncedChanges { get; set; }
|
||||||
|
public abstract List<string> ExcludePaths { get; }
|
||||||
|
|
||||||
public abstract bool AddExclusionRule (FileSystemEventArgs args);
|
public abstract double Size { get; }
|
||||||
public abstract bool RemoveExclusionRule (FileSystemEventArgs args);
|
public abstract double HistorySize { get; }
|
||||||
public abstract bool ExclusionRuleExists (FileSystemEventArgs args);
|
|
||||||
|
|
||||||
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
||||||
public event SyncStatusChangedEventHandler SyncStatusChanged;
|
public event SyncStatusChangedEventHandler SyncStatusChanged;
|
||||||
|
|
||||||
|
public delegate void SyncProgressChangedEventHandler (double percentage, string speed);
|
||||||
|
public event SyncProgressChangedEventHandler SyncProgressChanged;
|
||||||
|
|
||||||
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
|
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
|
||||||
public event NewChangeSetEventHandler NewChangeSet;
|
public event NewChangeSetEventHandler NewChangeSet;
|
||||||
|
|
||||||
public delegate void NewNoteEventHandler (string user_name, string user_email);
|
public delegate void NewNoteEventHandler (SparkleUser user);
|
||||||
public event NewNoteEventHandler NewNote;
|
public event NewNoteEventHandler NewNote;
|
||||||
|
|
||||||
public delegate void ConflictResolvedEventHandler ();
|
public delegate void ConflictResolvedEventHandler ();
|
||||||
|
@ -108,8 +114,6 @@ namespace SparkleLib {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.remote_timer.Elapsed += delegate {
|
this.remote_timer.Elapsed += delegate {
|
||||||
string identifier = Identifier;
|
|
||||||
|
|
||||||
bool time_to_poll = (DateTime.Compare (this.last_poll,
|
bool time_to_poll = (DateTime.Compare (this.last_poll,
|
||||||
DateTime.Now.Subtract (this.poll_interval)) < 0);
|
DateTime.Now.Subtract (this.poll_interval)) < 0);
|
||||||
|
|
||||||
|
@ -122,7 +126,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
// In the unlikely case that we haven't synced up our
|
// In the unlikely case that we haven't synced up our
|
||||||
// changes or the server was down, sync up again
|
// changes or the server was down, sync up again
|
||||||
if (HasUnsyncedChanges)
|
if (HasUnsyncedChanges && !IsSyncing && this.server_online)
|
||||||
SyncUpBase ();
|
SyncUpBase ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,6 +161,20 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public double ProgressPercentage {
|
||||||
|
get {
|
||||||
|
return this.progress_percentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string ProgressSpeed {
|
||||||
|
get {
|
||||||
|
return this.progress_speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual string [] UnsyncedFilePaths {
|
public virtual string [] UnsyncedFilePaths {
|
||||||
get {
|
get {
|
||||||
return new string [0];
|
return new string [0];
|
||||||
|
@ -186,7 +204,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual bool CheckForRemoteChanges () // HasRemoteChanges { get; } ?
|
public virtual bool CheckForRemoteChanges () // TODO: HasRemoteChanges { get; }
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -223,11 +241,8 @@ namespace SparkleLib {
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
this.remote_timer.Dispose ();
|
this.remote_timer.Dispose ();
|
||||||
this.remote_timer = null;
|
|
||||||
this.local_timer.Dispose ();
|
this.local_timer.Dispose ();
|
||||||
this.local_timer = null;
|
|
||||||
this.listener.Dispose ();
|
this.listener.Dispose ();
|
||||||
this.listener = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -301,7 +316,7 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool IsSyncing {
|
public bool IsSyncing {
|
||||||
get {
|
get {
|
||||||
return (Status == SyncStatus.SyncUp ||
|
return (Status == SyncStatus.SyncUp ||
|
||||||
Status == SyncStatus.SyncDown ||
|
Status == SyncStatus.SyncDown ||
|
||||||
|
@ -318,7 +333,7 @@ namespace SparkleLib {
|
||||||
this.sizebuffer.RemoveAt (0);
|
this.sizebuffer.RemoveAt (0);
|
||||||
|
|
||||||
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
||||||
this.sizebuffer.Add (CalculateFolderSize (dir_info));
|
this.sizebuffer.Add (CalculateSize (dir_info));
|
||||||
|
|
||||||
if (this.sizebuffer.Count >= 4 &&
|
if (this.sizebuffer.Count >= 4 &&
|
||||||
this.sizebuffer [0].Equals (this.sizebuffer [1]) &&
|
this.sizebuffer [0].Equals (this.sizebuffer [1]) &&
|
||||||
|
@ -347,40 +362,11 @@ namespace SparkleLib {
|
||||||
if (!this.watcher.EnableRaisingEvents)
|
if (!this.watcher.EnableRaisingEvents)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (args.FullPath.Contains (Path.DirectorySeparatorChar + ".") &&
|
string relative_path = args.FullPath.Replace (LocalPath, "");
|
||||||
!args.FullPath.Contains (Path.DirectorySeparatorChar + ".notes"))
|
|
||||||
|
foreach (string exclude_path in ExcludePaths) {
|
||||||
|
if (relative_path.Contains (exclude_path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether the file which triggered the action
|
|
||||||
* is readable so that git can actually commit it
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
if(File.Exists(args.FullPath)) {
|
|
||||||
FileStream file = File.OpenRead(args.FullPath);
|
|
||||||
file.Close();
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
if(!ExclusionRuleExists(args)) {
|
|
||||||
SparkleHelpers.DebugInfo("Warning", "File " + args.FullPath + " is not readable. Adding to ignore list.");
|
|
||||||
AddExclusionRule(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove rule if file is readable but there is still
|
|
||||||
* an exclusion rule set
|
|
||||||
*/
|
|
||||||
if(ExclusionRuleExists(args)) {
|
|
||||||
SparkleHelpers.DebugInfo("Info", "Removing exclusion rule for " + args.Name);
|
|
||||||
RemoveExclusionRule(args);
|
|
||||||
|
|
||||||
// If a file was former unreadable but has now been (re)moved, skip the process.
|
|
||||||
if(!File.Exists(args.FullPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
WatcherChangeTypes wct = args.ChangeType;
|
||||||
|
@ -402,7 +388,6 @@ namespace SparkleLib {
|
||||||
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + args.Name + "'");
|
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + args.Name + "'");
|
||||||
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] Changes found, checking if settled.");
|
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] Changes found, checking if settled.");
|
||||||
|
|
||||||
if (this.remote_timer != null)
|
|
||||||
this.remote_timer.Stop ();
|
this.remote_timer.Stop ();
|
||||||
|
|
||||||
lock (this.change_lock) {
|
lock (this.change_lock) {
|
||||||
|
@ -452,7 +437,6 @@ namespace SparkleLib {
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
DisableWatching ();
|
DisableWatching ();
|
||||||
if (this.remote_timer != null)
|
|
||||||
this.remote_timer.Stop ();
|
this.remote_timer.Stop ();
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("SyncUp", "[" + Name + "] Initiated");
|
SparkleHelpers.DebugInfo ("SyncUp", "[" + Name + "] Initiated");
|
||||||
|
@ -468,7 +452,6 @@ namespace SparkleLib {
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
if (this.listener != null)
|
|
||||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -476,26 +459,30 @@ namespace SparkleLib {
|
||||||
|
|
||||||
HasUnsyncedChanges = true;
|
HasUnsyncedChanges = true;
|
||||||
SyncDownBase ();
|
SyncDownBase ();
|
||||||
|
DisableWatching ();
|
||||||
|
|
||||||
if (SyncUp ()) {
|
if (this.server_online && SyncUp ()) {
|
||||||
HasUnsyncedChanges = false;
|
HasUnsyncedChanges = false;
|
||||||
|
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
if (this.listener != null)
|
|
||||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
this.server_online = false;
|
||||||
|
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Error);
|
SyncStatusChanged (SyncStatus.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (this.remote_timer != null)
|
|
||||||
this.remote_timer.Start ();
|
this.remote_timer.Start ();
|
||||||
EnableWatching ();
|
EnableWatching ();
|
||||||
|
|
||||||
|
this.progress_percentage = 0.0;
|
||||||
|
this.progress_speed = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +490,6 @@ namespace SparkleLib {
|
||||||
private void SyncDownBase ()
|
private void SyncDownBase ()
|
||||||
{
|
{
|
||||||
SparkleHelpers.DebugInfo ("SyncDown", "[" + Name + "] Initiated");
|
SparkleHelpers.DebugInfo ("SyncDown", "[" + Name + "] Initiated");
|
||||||
if (this.remote_timer != null)
|
|
||||||
this.remote_timer.Stop ();
|
this.remote_timer.Stop ();
|
||||||
DisableWatching ();
|
DisableWatching ();
|
||||||
|
|
||||||
|
@ -529,7 +515,7 @@ namespace SparkleLib {
|
||||||
foreach (string added in change_set.Added) {
|
foreach (string added in change_set.Added) {
|
||||||
if (added.Contains (".notes")) {
|
if (added.Contains (".notes")) {
|
||||||
if (NewNote != null)
|
if (NewNote != null)
|
||||||
NewNote (change_set.User.Name, change_set.User.Email);
|
NewNote (change_set.User);
|
||||||
|
|
||||||
note_added = true;
|
note_added = true;
|
||||||
break;
|
break;
|
||||||
|
@ -560,17 +546,18 @@ namespace SparkleLib {
|
||||||
if (SyncStatusChanged != null)
|
if (SyncStatusChanged != null)
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
if (this.remote_timer != null)
|
|
||||||
this.remote_timer.Start ();
|
this.remote_timer.Start ();
|
||||||
EnableWatching ();
|
EnableWatching ();
|
||||||
|
|
||||||
|
this.progress_percentage = 0.0;
|
||||||
|
this.progress_speed = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void DisableWatching ()
|
public void DisableWatching ()
|
||||||
{
|
{
|
||||||
lock (watch_lock) {
|
lock (this.watch_lock) {
|
||||||
this.watcher.EnableRaisingEvents = false;
|
this.watcher.EnableRaisingEvents = false;
|
||||||
if (this.local_timer != null)
|
|
||||||
this.local_timer.Stop ();
|
this.local_timer.Stop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,9 +565,8 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public void EnableWatching ()
|
public void EnableWatching ()
|
||||||
{
|
{
|
||||||
lock (watch_lock) {
|
lock (this.watch_lock) {
|
||||||
this.watcher.EnableRaisingEvents = true;
|
this.watcher.EnableRaisingEvents = true;
|
||||||
if (this.local_timer != null)
|
|
||||||
this.local_timer.Start ();
|
this.local_timer.Start ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -635,30 +621,15 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Recursively gets a folder's size in bytes
|
protected void OnSyncProgressChanged (double progress_percentage, string progress_speed)
|
||||||
private double CalculateFolderSize (DirectoryInfo parent)
|
|
||||||
{
|
{
|
||||||
if (!System.IO.Directory.Exists (parent.ToString ()))
|
// Console.WriteLine ("OnProgressChanged: " + progress_percentage + " " + progress_speed);
|
||||||
return 0;
|
|
||||||
|
|
||||||
double size = 0;
|
this.progress_percentage = progress_percentage;
|
||||||
|
this.progress_speed = progress_speed;
|
||||||
|
|
||||||
// Ignore the temporary 'rebase-apply' directory. This prevents potential
|
if (SyncProgressChanged != null)
|
||||||
// crashes when files are being queried whilst the files have already been deleted.
|
SyncProgressChanged (progress_percentage, progress_speed);
|
||||||
if (parent.Name.Equals ("rebase-apply"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
foreach (FileInfo file in parent.GetFiles ()) {
|
|
||||||
if (!file.Exists)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size += file.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (DirectoryInfo directory in parent.GetDirectories())
|
|
||||||
size += CalculateFolderSize (directory);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ namespace SparkleLib {
|
||||||
if (ChangeEvent != null)
|
if (ChangeEvent != null)
|
||||||
ChangeEvent (args);
|
ChangeEvent (args);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
<string>org.sparkleshare.sparkleshare</string>
|
<string>org.sparkleshare.sparkleshare</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>SparkleShare</string>
|
<string>SparkleShare</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>10.6</string>
|
<string>10.6</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>LSUIElement</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
|
|
|
@ -6,7 +6,6 @@ EXTRA_DIST = \
|
||||||
MainMenu.xib \
|
MainMenu.xib \
|
||||||
MainMenu.xib.designer.cs \
|
MainMenu.xib.designer.cs \
|
||||||
SparkleAbout.cs \
|
SparkleAbout.cs \
|
||||||
SparkleAlert.cs \
|
|
||||||
SparkleBadger.cs \
|
SparkleBadger.cs \
|
||||||
SparkleBubbles.cs \
|
SparkleBubbles.cs \
|
||||||
SparkleController.cs \
|
SparkleController.cs \
|
||||||
|
|
|
@ -57,6 +57,8 @@ namespace SparkleShare {
|
||||||
OrderFrontRegardless ();
|
OrderFrontRegardless ();
|
||||||
MakeKeyAndOrderFront (this);
|
MakeKeyAndOrderFront (this);
|
||||||
|
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
Controller.NewVersionEvent += delegate (string new_version) {
|
Controller.NewVersionEvent += delegate (string new_version) {
|
||||||
InvokeOnMainThread (delegate {
|
InvokeOnMainThread (delegate {
|
||||||
UpdatesTextField.StringValue = "A newer version (" + new_version + ") is available!";
|
UpdatesTextField.StringValue = "A newer version (" + new_version + ") is available!";
|
||||||
|
@ -161,6 +163,8 @@ namespace SparkleShare {
|
||||||
public override bool WindowShouldClose (NSObject sender)
|
public override bool WindowShouldClose (NSObject sender)
|
||||||
{
|
{
|
||||||
(sender as SparkleAbout).OrderOut (this);
|
(sender as SparkleAbout).OrderOut (this);
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
// SparkleShare, a collaboration and sharing tool.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using MonoMac.Foundation;
|
|
||||||
using MonoMac.AppKit;
|
|
||||||
using MonoMac.ObjCRuntime;
|
|
||||||
using MonoMac.WebKit;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleAlert : NSAlert {
|
|
||||||
|
|
||||||
public SparkleAlert () : base ()
|
|
||||||
{
|
|
||||||
MessageText = "SparkleShare couldn't find Git on your system. Do you want to download it?";
|
|
||||||
InformativeText = "Git is required to run SparkleShare.";
|
|
||||||
|
|
||||||
Icon = NSImage.ImageNamed ("sparkleshare.icns");
|
|
||||||
|
|
||||||
AddButton ("Download");
|
|
||||||
AddButton ("Cancel");
|
|
||||||
|
|
||||||
Buttons [0].Activated += delegate {
|
|
||||||
NSUrl url = new NSUrl ("http://code.google.com/p/git-osx-installer/downloads/list");
|
|
||||||
NSWorkspace.SharedWorkspace.OpenUrl (url);
|
|
||||||
Environment.Exit (0);
|
|
||||||
};
|
|
||||||
|
|
||||||
Buttons [1].Activated += delegate {
|
|
||||||
Environment.Exit (-1);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,6 +41,21 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleController () : base ()
|
public SparkleController () : base ()
|
||||||
{
|
{
|
||||||
|
string content_path =
|
||||||
|
Directory.GetParent (System.AppDomain.CurrentDomain.BaseDirectory)
|
||||||
|
.ToString ();
|
||||||
|
|
||||||
|
string app_path = Directory.GetParent (content_path).ToString ();
|
||||||
|
string growl_path = Path.Combine (app_path, "Frameworks", "Growl.framework", "Growl");
|
||||||
|
|
||||||
|
// Needed for Growl
|
||||||
|
Dlfcn.dlopen (growl_path, 0);
|
||||||
|
NSApplication.Init ();
|
||||||
|
|
||||||
|
// Let's use the bundled git first
|
||||||
|
SparkleBackend.DefaultBackend.Path =
|
||||||
|
Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
|
"git", "bin", "git");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -189,11 +204,10 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
new public void Quit ()
|
public override void OpenFile (string url)
|
||||||
{
|
{
|
||||||
this.watcher.Dispose ();
|
url = url.Replace ("%20", " ");
|
||||||
NSApplication.SharedApplication.Terminate (new NSObject ());
|
NSWorkspace.SharedWorkspace.OpenFile (url);
|
||||||
base.Quit ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using MonoMac.Foundation;
|
using MonoMac.Foundation;
|
||||||
|
@ -36,14 +35,17 @@ namespace SparkleShare {
|
||||||
PolicyDelegate = new SparkleWebPolicyDelegate ()
|
PolicyDelegate = new SparkleWebPolicyDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
private NSBox Separator = new NSBox (new RectangleF (0, 579, 480, 1)) {
|
private NSBox separator = new NSBox (new RectangleF (0, 579, 480, 1)) {
|
||||||
BorderColor = NSColor.LightGray,
|
BorderColor = NSColor.LightGray,
|
||||||
BoxType = NSBoxType.NSBoxCustom
|
BoxType = NSBoxType.NSBoxCustom
|
||||||
};
|
};
|
||||||
|
|
||||||
private NSPopUpButton popup_button;
|
private NSPopUpButton popup_button;
|
||||||
private NSProgressIndicator progress_indicator;
|
private NSProgressIndicator progress_indicator;
|
||||||
|
private NSTextField size_label;
|
||||||
|
private NSTextField size_label_value;
|
||||||
|
private NSTextField history_label;
|
||||||
|
private NSTextField history_label_value;
|
||||||
|
|
||||||
public SparkleEventLog (IntPtr handle) : base (handle) { }
|
public SparkleEventLog (IntPtr handle) : base (handle) { }
|
||||||
|
|
||||||
|
@ -65,7 +67,54 @@ namespace SparkleShare {
|
||||||
HasShadow = true;
|
HasShadow = true;
|
||||||
BackingType = NSBackingStore.Buffered;
|
BackingType = NSBackingStore.Buffered;
|
||||||
|
|
||||||
ContentView.AddSubview (Separator);
|
|
||||||
|
this.size_label = new NSTextField () {
|
||||||
|
Alignment = NSTextAlignment.Right,
|
||||||
|
BackgroundColor = NSColor.WindowBackground,
|
||||||
|
Bordered = false,
|
||||||
|
Editable = false,
|
||||||
|
Frame = new RectangleF (0, 588, 60, 20),
|
||||||
|
StringValue = "Size:",
|
||||||
|
Font = SparkleUI.BoldFont
|
||||||
|
};
|
||||||
|
|
||||||
|
this.size_label_value = new NSTextField () {
|
||||||
|
Alignment = NSTextAlignment.Left,
|
||||||
|
BackgroundColor = NSColor.WindowBackground,
|
||||||
|
Bordered = false,
|
||||||
|
Editable = false,
|
||||||
|
Frame = new RectangleF (60, 588, 75, 20),
|
||||||
|
StringValue = Controller.Size,
|
||||||
|
Font = SparkleUI.Font
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.history_label = new NSTextField () {
|
||||||
|
Alignment = NSTextAlignment.Right,
|
||||||
|
BackgroundColor = NSColor.WindowBackground,
|
||||||
|
Bordered = false,
|
||||||
|
Editable = false,
|
||||||
|
Frame = new RectangleF (130, 588, 60, 20),
|
||||||
|
StringValue = "History:",
|
||||||
|
Font = SparkleUI.BoldFont
|
||||||
|
};
|
||||||
|
|
||||||
|
this.history_label_value = new NSTextField () {
|
||||||
|
Alignment = NSTextAlignment.Left,
|
||||||
|
BackgroundColor = NSColor.WindowBackground,
|
||||||
|
Bordered = false,
|
||||||
|
Editable = false,
|
||||||
|
Frame = new RectangleF (190, 588, 75, 20),
|
||||||
|
StringValue = Controller.HistorySize,
|
||||||
|
Font = SparkleUI.Font
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ContentView.AddSubview (this.size_label);
|
||||||
|
ContentView.AddSubview (this.size_label_value);
|
||||||
|
ContentView.AddSubview (this.history_label);
|
||||||
|
ContentView.AddSubview (this.history_label_value);
|
||||||
|
ContentView.AddSubview (this.separator);
|
||||||
|
|
||||||
|
|
||||||
this.progress_indicator = new NSProgressIndicator () {
|
this.progress_indicator = new NSProgressIndicator () {
|
||||||
|
@ -81,6 +130,7 @@ namespace SparkleShare {
|
||||||
UpdateChooser (null);
|
UpdateChooser (null);
|
||||||
OrderFrontRegardless ();
|
OrderFrontRegardless ();
|
||||||
|
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
// Hook up the controller events
|
// Hook up the controller events
|
||||||
Controller.UpdateChooserEvent += delegate (string [] folders) {
|
Controller.UpdateChooserEvent += delegate (string [] folders) {
|
||||||
|
@ -103,6 +153,13 @@ namespace SparkleShare {
|
||||||
ContentView.AddSubview (this.progress_indicator);
|
ContentView.AddSubview (this.progress_indicator);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Controller.UpdateSizeInfoEvent += delegate (string size, string history_size) {
|
||||||
|
InvokeOnMainThread (delegate {
|
||||||
|
this.size_label_value.StringValue = size;
|
||||||
|
this.history_label_value.StringValue = history_size;
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,7 +180,7 @@ namespace SparkleShare {
|
||||||
this.popup_button.Font = NSFontManager.SharedFontManager.FontWithFamily
|
this.popup_button.Font = NSFontManager.SharedFontManager.FontWithFamily
|
||||||
("Lucida Grande", NSFontTraitMask.Condensed, 0, NSFont.SmallSystemFontSize);
|
("Lucida Grande", NSFontTraitMask.Condensed, 0, NSFont.SmallSystemFontSize);
|
||||||
|
|
||||||
this.popup_button.AddItem ("All Folders");
|
this.popup_button.AddItem ("All Projects");
|
||||||
this.popup_button.Menu.AddItem (NSMenuItem.SeparatorItem);
|
this.popup_button.Menu.AddItem (NSMenuItem.SeparatorItem);
|
||||||
this.popup_button.AddItems (folders);
|
this.popup_button.AddItems (folders);
|
||||||
|
|
||||||
|
@ -184,6 +241,8 @@ namespace SparkleShare {
|
||||||
public override bool WindowShouldClose (NSObject sender)
|
public override bool WindowShouldClose (NSObject sender)
|
||||||
{
|
{
|
||||||
(sender as SparkleEventLog).OrderOut (this);
|
(sender as SparkleEventLog).OrderOut (this);
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,30 +253,7 @@ namespace SparkleShare {
|
||||||
public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info,
|
public override void DecidePolicyForNavigation (WebView web_view, NSDictionary action_info,
|
||||||
NSUrlRequest request, WebFrame frame, NSObject decision_token)
|
NSUrlRequest request, WebFrame frame, NSObject decision_token)
|
||||||
{
|
{
|
||||||
string url = request.Url.ToString ();
|
SparkleEventLogController.LinkClicked (request.Url.ToString ());
|
||||||
|
|
||||||
if (url.StartsWith (Path.VolumeSeparatorChar.ToString ())) {
|
|
||||||
string file_path = request.Url.ToString ();
|
|
||||||
file_path = file_path.Replace ("%20", " ");
|
|
||||||
|
|
||||||
NSWorkspace.SharedWorkspace.OpenFile (file_path);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Regex regex = new Regex (@"(.+)~(.+)~(.+)");
|
|
||||||
Match match = regex.Match (url);
|
|
||||||
|
|
||||||
if (match.Success) {
|
|
||||||
string folder_name = match.Groups [1].Value;
|
|
||||||
string revision = match.Groups [2].Value;
|
|
||||||
string note = match.Groups [3].Value;
|
|
||||||
|
|
||||||
Thread thread = new Thread (new ThreadStart (delegate {
|
|
||||||
Program.Controller.AddNoteToFolder (folder_name, revision, note);
|
|
||||||
}));
|
|
||||||
|
|
||||||
thread.Start ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,9 @@ namespace SparkleShare {
|
||||||
public delegate void ChangedEventHandler (string path);
|
public delegate void ChangedEventHandler (string path);
|
||||||
public event ChangedEventHandler Changed;
|
public event ChangedEventHandler Changed;
|
||||||
|
|
||||||
private DirectoryInfo last_changed;
|
private FileSystemInfo last_changed;
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
private int poll_count = 0;
|
||||||
|
|
||||||
|
|
||||||
public SparkleMacWatcher (string path)
|
public SparkleMacWatcher (string path)
|
||||||
|
@ -50,7 +51,8 @@ namespace SparkleShare {
|
||||||
Changed (relative_path);
|
Changed (relative_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep (2500);
|
Thread.Sleep (7500);
|
||||||
|
this.poll_count++;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -73,7 +75,20 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception) { }
|
if (this.poll_count >= 8) {
|
||||||
|
foreach (FileInfo info in parent.GetFiles ()) {
|
||||||
|
if (!info.FullName.Contains ("/.")) {
|
||||||
|
if (DateTime.Compare (info.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
||||||
|
this.last_changed = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.poll_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception) {
|
||||||
|
// Don't care...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
using MonoMac.Foundation;
|
using MonoMac.Foundation;
|
||||||
|
@ -54,7 +52,9 @@ namespace SparkleShare {
|
||||||
private NSTextField PathLabel;
|
private NSTextField PathLabel;
|
||||||
private NSTextField PathHelpLabel;
|
private NSTextField PathHelpLabel;
|
||||||
private NSTextField AddProjectTextField;
|
private NSTextField AddProjectTextField;
|
||||||
private Timer timer;
|
private NSTextField WarningTextField;
|
||||||
|
private NSImage WarningImage;
|
||||||
|
private NSImageView WarningImageView;
|
||||||
private NSTableView TableView;
|
private NSTableView TableView;
|
||||||
private NSScrollView ScrollView;
|
private NSScrollView ScrollView;
|
||||||
private NSTableColumn IconColumn;
|
private NSTableColumn IconColumn;
|
||||||
|
@ -64,7 +64,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public SparkleSetup () : base ()
|
public SparkleSetup () : base ()
|
||||||
{
|
{
|
||||||
Controller.ChangePageEvent += delegate (PageType type) {
|
Controller.ChangePageEvent += delegate (PageType type, string [] warnings) {
|
||||||
InvokeOnMainThread (delegate {
|
InvokeOnMainThread (delegate {
|
||||||
Reset ();
|
Reset ();
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@ namespace SparkleShare {
|
||||||
case PageType.Setup: {
|
case PageType.Setup: {
|
||||||
|
|
||||||
Header = "Welcome to SparkleShare!";
|
Header = "Welcome to SparkleShare!";
|
||||||
Description = "Before we can create a SparkleShare folder on this " +
|
Description = "We'll need some info to mark your changes in the event log. " +
|
||||||
"computer, we need some information from you.";
|
"Don't worry, this stays between you and your peers.";
|
||||||
|
|
||||||
|
|
||||||
FullNameLabel = new NSTextField () {
|
FullNameLabel = new NSTextField () {
|
||||||
|
@ -88,7 +88,8 @@ namespace SparkleShare {
|
||||||
|
|
||||||
FullNameTextField = new NSTextField () {
|
FullNameTextField = new NSTextField () {
|
||||||
Frame = new RectangleF (330, Frame.Height - 238, 196, 22),
|
Frame = new RectangleF (330, Frame.Height - 238, 196, 22),
|
||||||
StringValue = Controller.GuessedUserName
|
StringValue = Controller.GuessedUserName,
|
||||||
|
Delegate = new SparkleTextFieldDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
EmailLabel = new NSTextField () {
|
EmailLabel = new NSTextField () {
|
||||||
|
@ -103,41 +104,44 @@ namespace SparkleShare {
|
||||||
|
|
||||||
EmailTextField = new NSTextField () {
|
EmailTextField = new NSTextField () {
|
||||||
Frame = new RectangleF (330, Frame.Height - 268, 196, 22),
|
Frame = new RectangleF (330, Frame.Height - 268, 196, 22),
|
||||||
StringValue = Controller.GuessedUserEmail
|
StringValue = Controller.GuessedUserEmail,
|
||||||
|
Delegate = new SparkleTextFieldDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Ugly hack, do properly with events
|
|
||||||
timer = new Timer () {
|
(FullNameTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
|
||||||
Interval = 50
|
Controller.CheckSetupPage (
|
||||||
|
FullNameTextField.StringValue,
|
||||||
|
EmailTextField.StringValue
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(EmailTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
|
||||||
|
Controller.CheckSetupPage (
|
||||||
|
FullNameTextField.StringValue,
|
||||||
|
EmailTextField.StringValue
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ContinueButton = new NSButton () {
|
ContinueButton = new NSButton () {
|
||||||
Title = "Continue",
|
Title = "Continue",
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ContinueButton.Activated += delegate {
|
ContinueButton.Activated += delegate {
|
||||||
timer.Stop ();
|
|
||||||
timer = null;
|
|
||||||
|
|
||||||
string full_name = FullNameTextField.StringValue.Trim ();
|
string full_name = FullNameTextField.StringValue.Trim ();
|
||||||
string email = EmailTextField.StringValue.Trim ();
|
string email = EmailTextField.StringValue.Trim ();
|
||||||
|
|
||||||
Controller.SetupPageCompleted (full_name, email);
|
Controller.SetupPageCompleted (full_name, email);
|
||||||
};
|
};
|
||||||
|
|
||||||
timer.Elapsed += delegate {
|
Controller.UpdateSetupContinueButtonEvent += delegate (bool button_enabled) {
|
||||||
InvokeOnMainThread (delegate {
|
InvokeOnMainThread (delegate {
|
||||||
bool name_is_valid = !FullNameTextField.StringValue.Trim ().Equals ("");
|
ContinueButton.Enabled = button_enabled;
|
||||||
|
|
||||||
bool email_is_valid = Program.Controller.IsValidEmail (
|
|
||||||
EmailTextField.StringValue.Trim ());
|
|
||||||
|
|
||||||
ContinueButton.Enabled = (name_is_valid && email_is_valid);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
timer.Start ();
|
|
||||||
|
|
||||||
ContentView.AddSubview (FullNameLabel);
|
ContentView.AddSubview (FullNameLabel);
|
||||||
ContentView.AddSubview (FullNameTextField);
|
ContentView.AddSubview (FullNameTextField);
|
||||||
|
@ -146,6 +150,11 @@ namespace SparkleShare {
|
||||||
|
|
||||||
Buttons.Add (ContinueButton);
|
Buttons.Add (ContinueButton);
|
||||||
|
|
||||||
|
Controller.CheckSetupPage (
|
||||||
|
FullNameTextField.StringValue,
|
||||||
|
EmailTextField.StringValue
|
||||||
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +177,8 @@ namespace SparkleShare {
|
||||||
Frame = new RectangleF (190, Frame.Height - 336, 196, 22),
|
Frame = new RectangleF (190, Frame.Height - 336, 196, 22),
|
||||||
Font = SparkleUI.Font,
|
Font = SparkleUI.Font,
|
||||||
StringValue = Controller.PreviousAddress,
|
StringValue = Controller.PreviousAddress,
|
||||||
Enabled = (Controller.SelectedPlugin.Address == null)
|
Enabled = (Controller.SelectedPlugin.Address == null),
|
||||||
|
Delegate = new SparkleTextFieldDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,7 +196,7 @@ namespace SparkleShare {
|
||||||
Frame = new RectangleF (190 + 196 + 16, Frame.Height - 336, 196, 22),
|
Frame = new RectangleF (190 + 196 + 16, Frame.Height - 336, 196, 22),
|
||||||
StringValue = Controller.PreviousPath,
|
StringValue = Controller.PreviousPath,
|
||||||
Enabled = (Controller.SelectedPlugin.Path == null),
|
Enabled = (Controller.SelectedPlugin.Path == null),
|
||||||
Bezeled = true
|
Delegate = new SparkleTextFieldDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,7 +220,8 @@ namespace SparkleShare {
|
||||||
Frame = new RectangleF (0, 0, 0, 0),
|
Frame = new RectangleF (0, 0, 0, 0),
|
||||||
RowHeight = 30,
|
RowHeight = 30,
|
||||||
IntercellSpacing = new SizeF (0, 12),
|
IntercellSpacing = new SizeF (0, 12),
|
||||||
HeaderView = null
|
HeaderView = null,
|
||||||
|
Delegate = new SparkleTableViewDelegate ()
|
||||||
};
|
};
|
||||||
|
|
||||||
ScrollView = new NSScrollView () {
|
ScrollView = new NSScrollView () {
|
||||||
|
@ -270,32 +281,42 @@ namespace SparkleShare {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TableView.SelectRow (Controller.SelectedPluginIndex, false);
|
TableView.SelectRow (Controller.SelectedPluginIndex, false);
|
||||||
|
|
||||||
|
|
||||||
timer = new Timer () {
|
(AddressTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
|
||||||
Interval = 50
|
Controller.CheckAddPage (
|
||||||
|
AddressTextField.StringValue,
|
||||||
|
PathTextField.StringValue,
|
||||||
|
TableView.SelectedRow
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Use an event
|
(PathTextField.Delegate as SparkleTextFieldDelegate).StringValueChanged += delegate {
|
||||||
timer.Elapsed += delegate {
|
Controller.CheckAddPage (
|
||||||
if (TableView.SelectedRow != Controller.SelectedPluginIndex)
|
AddressTextField.StringValue,
|
||||||
|
PathTextField.StringValue,
|
||||||
|
TableView.SelectedRow
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
(TableView.Delegate as SparkleTableViewDelegate).SelectionChanged += delegate {
|
||||||
Controller.SelectedPluginChanged (TableView.SelectedRow);
|
Controller.SelectedPluginChanged (TableView.SelectedRow);
|
||||||
|
|
||||||
InvokeOnMainThread (delegate {
|
Controller.CheckAddPage (
|
||||||
// TODO: Move checking logic to controller
|
AddressTextField.StringValue,
|
||||||
if (!string.IsNullOrWhiteSpace (AddressTextField.StringValue) &&
|
PathTextField.StringValue,
|
||||||
!string.IsNullOrWhiteSpace (PathTextField.StringValue)) {
|
TableView.SelectedRow
|
||||||
|
);
|
||||||
SyncButton.Enabled = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SyncButton.Enabled = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
timer.Start ();
|
|
||||||
|
Controller.UpdateAddProjectButtonEvent += delegate (bool button_enabled) {
|
||||||
|
InvokeOnMainThread (delegate {
|
||||||
|
SyncButton.Enabled = button_enabled;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ContentView.AddSubview (ScrollView);
|
ContentView.AddSubview (ScrollView);
|
||||||
|
@ -311,9 +332,6 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
SyncButton.Activated += delegate {
|
SyncButton.Activated += delegate {
|
||||||
timer.Stop ();
|
|
||||||
timer = null;
|
|
||||||
|
|
||||||
Controller.AddPageCompleted (
|
Controller.AddPageCompleted (
|
||||||
AddressTextField.StringValue,
|
AddressTextField.StringValue,
|
||||||
PathTextField.StringValue
|
PathTextField.StringValue
|
||||||
|
@ -334,6 +352,13 @@ namespace SparkleShare {
|
||||||
|
|
||||||
Buttons.Add (CancelButton);
|
Buttons.Add (CancelButton);
|
||||||
|
|
||||||
|
Controller.CheckAddPage (
|
||||||
|
AddressTextField.StringValue,
|
||||||
|
PathTextField.StringValue,
|
||||||
|
TableView.SelectedRow
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +467,28 @@ namespace SparkleShare {
|
||||||
"‘" + Controller.SyncingFolder + "’ in " +
|
"‘" + Controller.SyncingFolder + "’ in " +
|
||||||
"your SparkleShare folder.";
|
"your SparkleShare folder.";
|
||||||
|
|
||||||
|
if (warnings != null) {
|
||||||
|
WarningImage = NSImage.ImageNamed ("NSCaution");
|
||||||
|
WarningImage.Size = new SizeF (24, 24);
|
||||||
|
|
||||||
|
WarningImageView = new NSImageView () {
|
||||||
|
Image = WarningImage,
|
||||||
|
Frame = new RectangleF (190, Frame.Height - 175, 24, 24)
|
||||||
|
};
|
||||||
|
|
||||||
|
WarningTextField = new NSTextField () {
|
||||||
|
Frame = new RectangleF (230, Frame.Height - 245, 325, 100),
|
||||||
|
StringValue = warnings [0],
|
||||||
|
BackgroundColor = NSColor.WindowBackground,
|
||||||
|
Bordered = false,
|
||||||
|
Editable = false,
|
||||||
|
Font = SparkleUI.Font
|
||||||
|
};
|
||||||
|
|
||||||
|
ContentView.AddSubview (WarningImageView);
|
||||||
|
ContentView.AddSubview (WarningTextField);
|
||||||
|
}
|
||||||
|
|
||||||
FinishButton = new NSButton () {
|
FinishButton = new NSButton () {
|
||||||
Title = "Finish"
|
Title = "Finish"
|
||||||
};
|
};
|
||||||
|
@ -497,7 +544,7 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
"Pixmaps", "tutorial-slide-1.png");
|
"Pixmaps", "tutorial-slide-1-mac.png");
|
||||||
|
|
||||||
SlideImage = new NSImage (slide_image_path) {
|
SlideImage = new NSImage (slide_image_path) {
|
||||||
Size = new SizeF (350, 200)
|
Size = new SizeF (350, 200)
|
||||||
|
@ -529,7 +576,7 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
"Pixmaps", "tutorial-slide-2.png");
|
"Pixmaps", "tutorial-slide-2-mac.png");
|
||||||
|
|
||||||
SlideImage = new NSImage (slide_image_path) {
|
SlideImage = new NSImage (slide_image_path) {
|
||||||
Size = new SizeF (350, 200)
|
Size = new SizeF (350, 200)
|
||||||
|
@ -560,7 +607,7 @@ namespace SparkleShare {
|
||||||
};
|
};
|
||||||
|
|
||||||
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
string slide_image_path = Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||||
"Pixmaps", "tutorial-slide-3.png");
|
"Pixmaps", "tutorial-slide-3-mac.png");
|
||||||
|
|
||||||
SlideImage = new NSImage (slide_image_path) {
|
SlideImage = new NSImage (slide_image_path) {
|
||||||
Size = new SizeF (350, 200)
|
Size = new SizeF (350, 200)
|
||||||
|
@ -673,4 +720,39 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SparkleTextFieldDelegate : NSTextFieldDelegate {
|
||||||
|
|
||||||
|
public event StringValueChangedHandler StringValueChanged;
|
||||||
|
public delegate void StringValueChangedHandler ();
|
||||||
|
|
||||||
|
|
||||||
|
public override void Changed (NSNotification notification)
|
||||||
|
{
|
||||||
|
if (StringValueChanged!= null)
|
||||||
|
StringValueChanged ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override string [] GetCompletions (NSControl control, NSTextView text_view,
|
||||||
|
string [] a, MonoMac.Foundation.NSRange range, int b)
|
||||||
|
{
|
||||||
|
return new string [0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SparkleTableViewDelegate : NSTableViewDelegate {
|
||||||
|
|
||||||
|
public event SelectionChangedHandler SelectionChanged;
|
||||||
|
public delegate void SelectionChangedHandler ();
|
||||||
|
|
||||||
|
|
||||||
|
public override void SelectionDidChange (NSNotification notification)
|
||||||
|
{
|
||||||
|
if (SelectionChanged != null)
|
||||||
|
SelectionChanged ();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ namespace SparkleShare {
|
||||||
MakeKeyAndOrderFront (this);
|
MakeKeyAndOrderFront (this);
|
||||||
|
|
||||||
OrderFrontRegardless ();
|
OrderFrontRegardless ();
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,8 +144,10 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public override void PerformClose (NSObject sender)
|
public override void PerformClose (NSObject sender)
|
||||||
{
|
{
|
||||||
OrderOut (this);
|
base.OrderOut (this);
|
||||||
NSApplication.SharedApplication.RemoveWindowsItem (this);
|
NSApplication.SharedApplication.RemoveWindowsItem (this);
|
||||||
|
Program.UI.UpdateDockIconVisibility ();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<RootNamespace>SparkleShare</RootNamespace>
|
<RootNamespace>SparkleShare</RootNamespace>
|
||||||
<AssemblyName>SparkleShare</AssemblyName>
|
<AssemblyName>SparkleShare</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
<ReleaseVersion>0.2.5</ReleaseVersion>
|
<ReleaseVersion>0.6.0</ReleaseVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
<ConsolePause>false</ConsolePause>
|
<ConsolePause>false</ConsolePause>
|
||||||
<CustomCommands>
|
<CustomCommands>
|
||||||
<CustomCommands>
|
<CustomCommands>
|
||||||
<Command type="AfterBuild" command="mkdir -p ${TargetDir}/${SolutionName}.app/Contents/Frameworks; cp -r Growl.framework ${TargetDir}/${SolutionName}.app/Contents/Frameworks" externalConsole="true" />
|
<Command type="AfterBuild" command="mkdir -p ${TargetDir}/${SolutionName}.app/Contents/Frameworks; cp -r Growl.framework ${TargetDir}/${SolutionName}.app/Contents/Frameworks;mkdir -p ${TargetDir}/${SolutionName}.app/Contents/Resources; cp -r git ${TargetDir}/${SolutionName}.app/Contents/Resources" externalConsole="true" />
|
||||||
</CustomCommands>
|
</CustomCommands>
|
||||||
</CustomCommands>
|
</CustomCommands>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -58,15 +58,11 @@
|
||||||
<Reference Include="Mono.Posix">
|
<Reference Include="Mono.Posix">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Meebey.SmartIrc4net, Version=0.4.5.0, Culture=neutral, PublicKeyToken=7868485fbf407e0f">
|
<Reference Include="System.Net" />
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<Reference Include="SparkleLib, Version=0.6.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>..\..\bin\Meebey.SmartIrc4net.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="SparkleLib, Version=0.2.5.0, Culture=neutral, PublicKeyToken=null">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
|
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Net" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AppDelegate.cs">
|
<Compile Include="AppDelegate.cs">
|
||||||
|
@ -83,8 +79,6 @@
|
||||||
<Compile Include="..\Program.cs">
|
<Compile Include="..\Program.cs">
|
||||||
<Link>Program.cs</Link>
|
<Link>Program.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="SparkleAbout.cs" />
|
|
||||||
<Compile Include="SparkleAlert.cs" />
|
|
||||||
<Compile Include="SparkleMacWatcher.cs" />
|
<Compile Include="SparkleMacWatcher.cs" />
|
||||||
<Compile Include="SparkleEventLog.cs" />
|
<Compile Include="SparkleEventLog.cs" />
|
||||||
<Compile Include="SparkleBadger.cs" />
|
<Compile Include="SparkleBadger.cs" />
|
||||||
|
@ -113,6 +107,13 @@
|
||||||
<Compile Include="..\SparklePlugin.cs">
|
<Compile Include="..\SparklePlugin.cs">
|
||||||
<Link>SparklePlugin.cs</Link>
|
<Link>SparklePlugin.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\SparkleOptions.cs">
|
||||||
|
<Link>SparkleOptions.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="SparkleAbout.cs" />
|
||||||
|
<Compile Include="..\SparkleInvite.cs">
|
||||||
|
<Link>SparkleInvite.cs</Link>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="MainMenu.xib" />
|
<Page Include="MainMenu.xib" />
|
||||||
|
@ -277,6 +278,15 @@
|
||||||
<Content Include="..\..\data\tutorial-slide-1.png">
|
<Content Include="..\..\data\tutorial-slide-1.png">
|
||||||
<Link>Pixmaps\tutorial-slide-1.png</Link>
|
<Link>Pixmaps\tutorial-slide-1.png</Link>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="..\..\data\tutorial-slide-1-mac.png">
|
||||||
|
<Link>Pixmaps\tutorial-slide-1-mac.png</Link>
|
||||||
|
</Content>
|
||||||
|
<Content Include="..\..\data\tutorial-slide-2-mac.png">
|
||||||
|
<Link>Pixmaps\tutorial-slide-2-mac.png</Link>
|
||||||
|
</Content>
|
||||||
|
<Content Include="..\..\data\tutorial-slide-3-mac.png">
|
||||||
|
<Link>Pixmaps\tutorial-slide-3-mac.png</Link>
|
||||||
|
</Content>
|
||||||
<Content Include="..\..\data\tutorial-slide-2.png">
|
<Content Include="..\..\data\tutorial-slide-2.png">
|
||||||
<Link>Pixmaps\tutorial-slide-2.png</Link>
|
<Link>Pixmaps\tutorial-slide-2.png</Link>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
2
SparkleShare/Mac/SparkleShare.sln
Executable file → Normal file
2
SparkleShare/Mac/SparkleShare.sln
Executable file → Normal file
|
@ -16,6 +16,6 @@ Global
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
StartupItem = SparkleShare.csproj
|
StartupItem = SparkleShare.csproj
|
||||||
version = 0.2.5
|
version = 0.6.0
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace SparkleShare {
|
||||||
private NSMenuItem AboutMenuItem;
|
private NSMenuItem AboutMenuItem;
|
||||||
private NSMenuItem NotificationsMenuItem;
|
private NSMenuItem NotificationsMenuItem;
|
||||||
private NSMenuItem RecentEventsMenuItem;
|
private NSMenuItem RecentEventsMenuItem;
|
||||||
|
private NSMenuItem QuitMenuItem;
|
||||||
private NSImage [] AnimationFrames;
|
private NSImage [] AnimationFrames;
|
||||||
private NSImage [] AnimationFramesActive;
|
private NSImage [] AnimationFramesActive;
|
||||||
private NSImage ErrorImage;
|
private NSImage ErrorImage;
|
||||||
|
@ -110,7 +111,10 @@ namespace SparkleShare {
|
||||||
|
|
||||||
case IconState.Syncing:
|
case IconState.Syncing:
|
||||||
|
|
||||||
StateText = _("Syncing…");
|
StateText = _("Syncing… " +
|
||||||
|
Controller.ProgressPercentage + "% " +
|
||||||
|
Controller.ProgressSpeed);
|
||||||
|
|
||||||
StateMenuItem.Title = StateText;
|
StateMenuItem.Title = StateText;
|
||||||
|
|
||||||
if (!Animation.Enabled)
|
if (!Animation.Enabled)
|
||||||
|
@ -120,6 +124,8 @@ namespace SparkleShare {
|
||||||
|
|
||||||
case IconState.Error:
|
case IconState.Error:
|
||||||
|
|
||||||
|
Animation.Stop ();
|
||||||
|
|
||||||
StateText = _("Not everything is synced");
|
StateText = _("Not everything is synced");
|
||||||
StateMenuItem.Title = StateText;
|
StateMenuItem.Title = StateText;
|
||||||
CreateMenu ();
|
CreateMenu ();
|
||||||
|
@ -240,7 +246,7 @@ namespace SparkleShare {
|
||||||
|
|
||||||
RecentEventsMenuItem = new NSMenuItem () {
|
RecentEventsMenuItem = new NSMenuItem () {
|
||||||
Title = "Open Recent Events",
|
Title = "Open Recent Events",
|
||||||
Enabled = true
|
Enabled = (Controller.Folders.Length > 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Controller.Folders.Length > 0) {
|
if (Controller.Folders.Length > 0) {
|
||||||
|
@ -299,8 +305,20 @@ namespace SparkleShare {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Menu.AddItem (AboutMenuItem);
|
Menu.AddItem (AboutMenuItem);
|
||||||
|
Menu.AddItem (NSMenuItem.SeparatorItem);
|
||||||
|
|
||||||
|
|
||||||
|
QuitMenuItem = new NSMenuItem () {
|
||||||
|
Title = "Quit",
|
||||||
|
Enabled = true
|
||||||
|
};
|
||||||
|
|
||||||
|
QuitMenuItem.Activated += delegate {
|
||||||
|
Program.Controller.Quit ();
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.AddItem (QuitMenuItem);
|
||||||
|
|
||||||
StatusItem.Menu = Menu;
|
StatusItem.Menu = Menu;
|
||||||
StatusItem.Menu.Update ();
|
StatusItem.Menu.Update ();
|
||||||
|
|
|
@ -37,22 +37,11 @@ namespace SparkleShare {
|
||||||
public static SparkleBubbles Bubbles;
|
public static SparkleBubbles Bubbles;
|
||||||
public static SparkleAbout About;
|
public static SparkleAbout About;
|
||||||
public static NSFont Font;
|
public static NSFont Font;
|
||||||
|
public static NSFont BoldFont;
|
||||||
private NSAlert alert;
|
|
||||||
|
|
||||||
|
|
||||||
public SparkleUI ()
|
public SparkleUI ()
|
||||||
{
|
{
|
||||||
string content_path = Directory.GetParent (
|
|
||||||
System.AppDomain.CurrentDomain.BaseDirectory).ToString ();
|
|
||||||
|
|
||||||
string app_path = Directory.GetParent (content_path).ToString ();
|
|
||||||
string growl_path = Path.Combine (app_path, "Frameworks", "Growl.framework", "Growl");
|
|
||||||
|
|
||||||
// Needed for Growl
|
|
||||||
Dlfcn.dlopen (growl_path, 0);
|
|
||||||
NSApplication.Init ();
|
|
||||||
|
|
||||||
// Use translations
|
// Use translations
|
||||||
Catalog.Init ("sparkleshare",
|
Catalog.Init ("sparkleshare",
|
||||||
Path.Combine (NSBundle.MainBundle.ResourcePath, "Translations"));
|
Path.Combine (NSBundle.MainBundle.ResourcePath, "Translations"));
|
||||||
|
@ -66,17 +55,14 @@ namespace SparkleShare {
|
||||||
NSApplication.SharedApplication.ApplicationIconImage
|
NSApplication.SharedApplication.ApplicationIconImage
|
||||||
= NSImage.ImageNamed ("sparkleshare.icns");
|
= NSImage.ImageNamed ("sparkleshare.icns");
|
||||||
|
|
||||||
if (!Program.Controller.BackendIsPresent) {
|
|
||||||
this.alert = new SparkleAlert ();
|
|
||||||
this.alert.RunModal ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetFolderIcon ();
|
SetFolderIcon ();
|
||||||
|
|
||||||
Font = NSFontManager.SharedFontManager.FontWithFamily
|
Font = NSFontManager.SharedFontManager.FontWithFamily
|
||||||
("Lucida Grande", NSFontTraitMask.Condensed, 0, 13);
|
("Lucida Grande", NSFontTraitMask.Condensed, 0, 13);
|
||||||
|
|
||||||
|
BoldFont = NSFontManager.SharedFontManager.FontWithFamily
|
||||||
|
("Lucida Grande", NSFontTraitMask.Bold, 0, 13);
|
||||||
|
|
||||||
StatusIcon = new SparkleStatusIcon ();
|
StatusIcon = new SparkleStatusIcon ();
|
||||||
Bubbles = new SparkleBubbles ();
|
Bubbles = new SparkleBubbles ();
|
||||||
|
|
||||||
|
@ -106,6 +92,29 @@ namespace SparkleShare {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void UpdateDockIconVisibility ()
|
||||||
|
{
|
||||||
|
if (true) { // TODO: check for open windows
|
||||||
|
|
||||||
|
ShowDockIcon ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
HideDockIcon ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void HideDockIcon () {
|
||||||
|
// Currently not supported, here for completeness sake (see Apple's docs)
|
||||||
|
// NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ShowDockIcon () {
|
||||||
|
NSApplication.SharedApplication.ActivationPolicy = NSApplicationActivationPolicy.Regular;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Export("registrationDictionaryForGrowl")]
|
[Export("registrationDictionaryForGrowl")]
|
||||||
NSDictionary RegistrationDictionaryForGrowl ()
|
NSDictionary RegistrationDictionaryForGrowl ()
|
||||||
{
|
{
|
||||||
|
@ -122,6 +131,7 @@ namespace SparkleShare {
|
||||||
NSApplication.SharedApplication.DockTile.BadgeLabel = null;
|
NSApplication.SharedApplication.DockTile.BadgeLabel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void WillTerminate (NSNotification notification)
|
public override void WillTerminate (NSNotification notification)
|
||||||
{
|
{
|
||||||
Program.Controller.Quit ();
|
Program.Controller.Quit ();
|
||||||
|
|
370
SparkleShare/Mac/git/LICENSE
Normal file
370
SparkleShare/Mac/git/LICENSE
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
From https://github.com/gitster/git:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GIT - the stupid content tracker
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
"git" can mean anything, depending on your mood.
|
||||||
|
|
||||||
|
- random three-letter combination that is pronounceable, and not
|
||||||
|
actually used by any common UNIX command. The fact that it is a
|
||||||
|
mispronunciation of "get" may or may not be relevant.
|
||||||
|
- stupid. contemptible and despicable. simple. Take your pick from the
|
||||||
|
dictionary of slang.
|
||||||
|
- "global information tracker": you're in a good mood, and it actually
|
||||||
|
works for you. Angels sing, and a light suddenly fills the room.
|
||||||
|
- "goddamn idiotic truckload of sh*t": when it breaks
|
||||||
|
|
||||||
|
Git is a fast, scalable, distributed revision control system with an
|
||||||
|
unusually rich command set that provides both high-level operations
|
||||||
|
and full access to internals.
|
||||||
|
|
||||||
|
Git is an Open Source project covered by the GNU General Public License.
|
||||||
|
It was originally written by Linus Torvalds with help of a group of
|
||||||
|
hackers around the net. It is currently maintained by Junio C Hamano.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
BIN
SparkleShare/Mac/git/bin/git
Executable file
BIN
SparkleShare/Mac/git/bin/git
Executable file
Binary file not shown.
3696
SparkleShare/Mac/git/bin/git-cvsserver
Executable file
3696
SparkleShare/Mac/git/bin/git-cvsserver
Executable file
File diff suppressed because it is too large
Load diff
1
SparkleShare/Mac/git/bin/git-receive-pack
Symbolic link
1
SparkleShare/Mac/git/bin/git-receive-pack
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
git
|
BIN
SparkleShare/Mac/git/bin/git-shell
Executable file
BIN
SparkleShare/Mac/git/bin/git-shell
Executable file
Binary file not shown.
1
SparkleShare/Mac/git/bin/git-upload-archive
Symbolic link
1
SparkleShare/Mac/git/bin/git-upload-archive
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
git
|
BIN
SparkleShare/Mac/git/bin/git-upload-pack
Executable file
BIN
SparkleShare/Mac/git/bin/git-upload-pack
Executable file
Binary file not shown.
11702
SparkleShare/Mac/git/bin/gitk
Executable file
11702
SparkleShare/Mac/git/bin/gitk
Executable file
File diff suppressed because it is too large
Load diff
1
SparkleShare/Mac/git/libexec/git-core/git
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-add
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-add
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1610
SparkleShare/Mac/git/libexec/git-core/git-add--interactive
Executable file
1610
SparkleShare/Mac/git/libexec/git-core/git-add--interactive
Executable file
File diff suppressed because it is too large
Load diff
841
SparkleShare/Mac/git/libexec/git-core/git-am
Executable file
841
SparkleShare/Mac/git/libexec/git-core/git-am
Executable file
|
@ -0,0 +1,841 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005, 2006 Junio C Hamano
|
||||||
|
|
||||||
|
SUBDIRECTORY_OK=Yes
|
||||||
|
OPTIONS_KEEPDASHDASH=
|
||||||
|
OPTIONS_SPEC="\
|
||||||
|
git am [options] [(<mbox>|<Maildir>)...]
|
||||||
|
git am [options] (--resolved | --skip | --abort)
|
||||||
|
--
|
||||||
|
i,interactive run interactively
|
||||||
|
b,binary* (historical option -- no-op)
|
||||||
|
3,3way allow fall back on 3way merging if needed
|
||||||
|
q,quiet be quiet
|
||||||
|
s,signoff add a Signed-off-by line to the commit message
|
||||||
|
u,utf8 recode into utf8 (default)
|
||||||
|
k,keep pass -k flag to git-mailinfo
|
||||||
|
keep-cr pass --keep-cr flag to git-mailsplit for mbox format
|
||||||
|
no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
|
||||||
|
c,scissors strip everything before a scissors line
|
||||||
|
whitespace= pass it through git-apply
|
||||||
|
ignore-space-change pass it through git-apply
|
||||||
|
ignore-whitespace pass it through git-apply
|
||||||
|
directory= pass it through git-apply
|
||||||
|
C= pass it through git-apply
|
||||||
|
p= pass it through git-apply
|
||||||
|
patch-format= format the patch(es) are in
|
||||||
|
reject pass it through git-apply
|
||||||
|
resolvemsg= override error message when patch failure occurs
|
||||||
|
continue continue applying patches after resolving a conflict
|
||||||
|
r,resolved synonyms for --continue
|
||||||
|
skip skip the current patch
|
||||||
|
abort restore the original branch and abort the patching operation.
|
||||||
|
committer-date-is-author-date lie about committer date
|
||||||
|
ignore-date use current timestamp for author date
|
||||||
|
rerere-autoupdate update the index with reused conflict resolution if possible
|
||||||
|
rebasing* (internal use for git-rebase)"
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
prefix=$(git rev-parse --show-prefix)
|
||||||
|
set_reflog_action am
|
||||||
|
require_work_tree
|
||||||
|
cd_to_toplevel
|
||||||
|
|
||||||
|
git var GIT_COMMITTER_IDENT >/dev/null ||
|
||||||
|
die "You need to set your committer info first"
|
||||||
|
|
||||||
|
if git rev-parse --verify -q HEAD >/dev/null
|
||||||
|
then
|
||||||
|
HAS_HEAD=yes
|
||||||
|
else
|
||||||
|
HAS_HEAD=
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmdline="git am"
|
||||||
|
if test '' != "$interactive"
|
||||||
|
then
|
||||||
|
cmdline="$cmdline -i"
|
||||||
|
fi
|
||||||
|
if test '' != "$threeway"
|
||||||
|
then
|
||||||
|
cmdline="$cmdline -3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sq () {
|
||||||
|
git rev-parse --sq-quote "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_here () {
|
||||||
|
echo "$1" >"$dotest/next"
|
||||||
|
git rev-parse --verify -q HEAD >"$dotest/abort-safety"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_to_abort () {
|
||||||
|
if test -f "$dotest/dirtyindex"
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! test -s "$dotest/abort-safety"
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
abort_safety=$(cat "$dotest/abort-safety")
|
||||||
|
if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety"
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo >&2 "You seem to have moved HEAD since the last 'am' failure."
|
||||||
|
echo >&2 "Not rewinding to ORIG_HEAD"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_here_user_resolve () {
|
||||||
|
if [ -n "$resolvemsg" ]; then
|
||||||
|
printf '%s\n' "$resolvemsg"
|
||||||
|
stop_here $1
|
||||||
|
fi
|
||||||
|
echo "When you have resolved this problem run \"$cmdline --resolved\"."
|
||||||
|
echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
|
||||||
|
echo "To restore the original branch and stop patching run \"$cmdline --abort\"."
|
||||||
|
|
||||||
|
stop_here $1
|
||||||
|
}
|
||||||
|
|
||||||
|
go_next () {
|
||||||
|
rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \
|
||||||
|
"$dotest/patch" "$dotest/info"
|
||||||
|
echo "$next" >"$dotest/next"
|
||||||
|
this=$next
|
||||||
|
}
|
||||||
|
|
||||||
|
cannot_fallback () {
|
||||||
|
echo "$1"
|
||||||
|
echo "Cannot fall back to three-way merge."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fall_back_3way () {
|
||||||
|
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
|
||||||
|
|
||||||
|
rm -fr "$dotest"/patch-merge-*
|
||||||
|
mkdir "$dotest/patch-merge-tmp-dir"
|
||||||
|
|
||||||
|
# First see if the patch records the index info that we can use.
|
||||||
|
git apply --build-fake-ancestor "$dotest/patch-merge-tmp-index" \
|
||||||
|
"$dotest/patch" &&
|
||||||
|
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||||
|
git write-tree >"$dotest/patch-merge-base+" ||
|
||||||
|
cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
|
||||||
|
|
||||||
|
say Using index info to reconstruct a base tree...
|
||||||
|
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||||
|
git apply --cached <"$dotest/patch"
|
||||||
|
then
|
||||||
|
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
|
||||||
|
mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
|
||||||
|
else
|
||||||
|
cannot_fallback "Did you hand edit your patch?
|
||||||
|
It does not apply to blobs recorded in its index."
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -f "$dotest/patch-merge-index" &&
|
||||||
|
his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree) &&
|
||||||
|
orig_tree=$(cat "$dotest/patch-merge-base") &&
|
||||||
|
rm -fr "$dotest"/patch-merge-* || exit 1
|
||||||
|
|
||||||
|
say Falling back to patching base and 3-way merge...
|
||||||
|
|
||||||
|
# This is not so wrong. Depending on which base we picked,
|
||||||
|
# orig_tree may be wildly different from ours, but his_tree
|
||||||
|
# has the same set of wildly different changes in parts the
|
||||||
|
# patch did not touch, so recursive ends up canceling them,
|
||||||
|
# saying that we reverted all those changes.
|
||||||
|
|
||||||
|
eval GITHEAD_$his_tree='"$FIRSTLINE"'
|
||||||
|
export GITHEAD_$his_tree
|
||||||
|
if test -n "$GIT_QUIET"
|
||||||
|
then
|
||||||
|
GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
|
||||||
|
fi
|
||||||
|
git-merge-recursive $orig_tree -- HEAD $his_tree || {
|
||||||
|
git rerere $allow_rerere_autoupdate
|
||||||
|
echo Failed to merge in the changes.
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
unset GITHEAD_$his_tree
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_abort () {
|
||||||
|
test $# = 0 || echo >&2 "$@"
|
||||||
|
rm -fr "$dotest"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_format=
|
||||||
|
|
||||||
|
check_patch_format () {
|
||||||
|
# early return if patch_format was set from the command line
|
||||||
|
if test -n "$patch_format"
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# we default to mbox format if input is from stdin and for
|
||||||
|
# directories
|
||||||
|
if test $# = 0 || test "x$1" = "x-" || test -d "$1"
|
||||||
|
then
|
||||||
|
patch_format=mbox
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# otherwise, check the first few lines of the first patch to try
|
||||||
|
# to detect its format
|
||||||
|
{
|
||||||
|
read l1
|
||||||
|
read l2
|
||||||
|
read l3
|
||||||
|
case "$l1" in
|
||||||
|
"From "* | "From: "*)
|
||||||
|
patch_format=mbox
|
||||||
|
;;
|
||||||
|
'# This series applies on GIT commit'*)
|
||||||
|
patch_format=stgit-series
|
||||||
|
;;
|
||||||
|
"# HG changeset patch")
|
||||||
|
patch_format=hg
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# if the second line is empty and the third is
|
||||||
|
# a From, Author or Date entry, this is very
|
||||||
|
# likely an StGIT patch
|
||||||
|
case "$l2,$l3" in
|
||||||
|
,"From: "* | ,"Author: "* | ,"Date: "*)
|
||||||
|
patch_format=stgit
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if test -z "$patch_format" &&
|
||||||
|
test -n "$l1" &&
|
||||||
|
test -n "$l2" &&
|
||||||
|
test -n "$l3"
|
||||||
|
then
|
||||||
|
# This begins with three non-empty lines. Is this a
|
||||||
|
# piece of e-mail a-la RFC2822? Grab all the headers,
|
||||||
|
# discarding the indented remainder of folded lines,
|
||||||
|
# and see if it looks like that they all begin with the
|
||||||
|
# header field names...
|
||||||
|
tr -d '\015' <"$1" |
|
||||||
|
sed -n -e '/^$/q' -e '/^[ ]/d' -e p |
|
||||||
|
sane_egrep -v '^[!-9;-~]+:' >/dev/null ||
|
||||||
|
patch_format=mbox
|
||||||
|
fi
|
||||||
|
} < "$1" || clean_abort
|
||||||
|
}
|
||||||
|
|
||||||
|
split_patches () {
|
||||||
|
case "$patch_format" in
|
||||||
|
mbox)
|
||||||
|
if test -n "$rebasing" || test t = "$keepcr"
|
||||||
|
then
|
||||||
|
keep_cr=--keep-cr
|
||||||
|
else
|
||||||
|
keep_cr=
|
||||||
|
fi
|
||||||
|
git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" ||
|
||||||
|
clean_abort
|
||||||
|
;;
|
||||||
|
stgit-series)
|
||||||
|
if test $# -ne 1
|
||||||
|
then
|
||||||
|
clean_abort "Only one StGIT patch series can be applied at once"
|
||||||
|
fi
|
||||||
|
series_dir=`dirname "$1"`
|
||||||
|
series_file="$1"
|
||||||
|
shift
|
||||||
|
{
|
||||||
|
set x
|
||||||
|
while read filename
|
||||||
|
do
|
||||||
|
set "$@" "$series_dir/$filename"
|
||||||
|
done
|
||||||
|
# remove the safety x
|
||||||
|
shift
|
||||||
|
# remove the arg coming from the first-line comment
|
||||||
|
shift
|
||||||
|
} < "$series_file" || clean_abort
|
||||||
|
# set the patch format appropriately
|
||||||
|
patch_format=stgit
|
||||||
|
# now handle the actual StGIT patches
|
||||||
|
split_patches "$@"
|
||||||
|
;;
|
||||||
|
stgit)
|
||||||
|
this=0
|
||||||
|
for stgit in "$@"
|
||||||
|
do
|
||||||
|
this=`expr "$this" + 1`
|
||||||
|
msgnum=`printf "%0${prec}d" $this`
|
||||||
|
# Perl version of StGIT parse_patch. The first nonemptyline
|
||||||
|
# not starting with Author, From or Date is the
|
||||||
|
# subject, and the body starts with the next nonempty
|
||||||
|
# line not starting with Author, From or Date
|
||||||
|
perl -ne 'BEGIN { $subject = 0 }
|
||||||
|
if ($subject > 1) { print ; }
|
||||||
|
elsif (/^\s+$/) { next ; }
|
||||||
|
elsif (/^Author:/) { print s/Author/From/ ; }
|
||||||
|
elsif (/^(From|Date)/) { print ; }
|
||||||
|
elsif ($subject) {
|
||||||
|
$subject = 2 ;
|
||||||
|
print "\n" ;
|
||||||
|
print ;
|
||||||
|
} else {
|
||||||
|
print "Subject: ", $_ ;
|
||||||
|
$subject = 1;
|
||||||
|
}
|
||||||
|
' < "$stgit" > "$dotest/$msgnum" || clean_abort
|
||||||
|
done
|
||||||
|
echo "$this" > "$dotest/last"
|
||||||
|
this=
|
||||||
|
msgnum=
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if test -n "$parse_patch" ; then
|
||||||
|
clean_abort "Patch format $patch_format is not supported."
|
||||||
|
else
|
||||||
|
clean_abort "Patch format detection failed."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
prec=4
|
||||||
|
dotest="$GIT_DIR/rebase-apply"
|
||||||
|
sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
|
||||||
|
resolvemsg= resume= scissors= no_inbody_headers=
|
||||||
|
git_apply_opt=
|
||||||
|
committer_date_is_author_date=
|
||||||
|
ignore_date=
|
||||||
|
allow_rerere_autoupdate=
|
||||||
|
|
||||||
|
if test "$(git config --bool --get am.keepcr)" = true
|
||||||
|
then
|
||||||
|
keepcr=t
|
||||||
|
fi
|
||||||
|
|
||||||
|
while test $# != 0
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-i|--interactive)
|
||||||
|
interactive=t ;;
|
||||||
|
-b|--binary)
|
||||||
|
: ;;
|
||||||
|
-3|--3way)
|
||||||
|
threeway=t ;;
|
||||||
|
-s|--signoff)
|
||||||
|
sign=t ;;
|
||||||
|
-u|--utf8)
|
||||||
|
utf8=t ;; # this is now default
|
||||||
|
--no-utf8)
|
||||||
|
utf8= ;;
|
||||||
|
-k|--keep)
|
||||||
|
keep=t ;;
|
||||||
|
-c|--scissors)
|
||||||
|
scissors=t ;;
|
||||||
|
--no-scissors)
|
||||||
|
scissors=f ;;
|
||||||
|
-r|--resolved|--continue)
|
||||||
|
resolved=t ;;
|
||||||
|
--skip)
|
||||||
|
skip=t ;;
|
||||||
|
--abort)
|
||||||
|
abort=t ;;
|
||||||
|
--rebasing)
|
||||||
|
rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;;
|
||||||
|
-d|--dotest)
|
||||||
|
die "-d option is no longer supported. Do not use."
|
||||||
|
;;
|
||||||
|
--resolvemsg)
|
||||||
|
shift; resolvemsg=$1 ;;
|
||||||
|
--whitespace|--directory)
|
||||||
|
git_apply_opt="$git_apply_opt $(sq "$1=$2")"; shift ;;
|
||||||
|
-C|-p)
|
||||||
|
git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;;
|
||||||
|
--patch-format)
|
||||||
|
shift ; patch_format="$1" ;;
|
||||||
|
--reject|--ignore-whitespace|--ignore-space-change)
|
||||||
|
git_apply_opt="$git_apply_opt $1" ;;
|
||||||
|
--committer-date-is-author-date)
|
||||||
|
committer_date_is_author_date=t ;;
|
||||||
|
--ignore-date)
|
||||||
|
ignore_date=t ;;
|
||||||
|
--rerere-autoupdate|--no-rerere-autoupdate)
|
||||||
|
allow_rerere_autoupdate="$1" ;;
|
||||||
|
-q|--quiet)
|
||||||
|
GIT_QUIET=t ;;
|
||||||
|
--keep-cr)
|
||||||
|
keepcr=t ;;
|
||||||
|
--no-keep-cr)
|
||||||
|
keepcr=f ;;
|
||||||
|
--)
|
||||||
|
shift; break ;;
|
||||||
|
*)
|
||||||
|
usage ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# If the dotest directory exists, but we have finished applying all the
|
||||||
|
# patches in them, clear it out.
|
||||||
|
if test -d "$dotest" &&
|
||||||
|
last=$(cat "$dotest/last") &&
|
||||||
|
next=$(cat "$dotest/next") &&
|
||||||
|
test $# != 0 &&
|
||||||
|
test "$next" -gt "$last"
|
||||||
|
then
|
||||||
|
rm -fr "$dotest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -d "$dotest"
|
||||||
|
then
|
||||||
|
case "$#,$skip$resolved$abort" in
|
||||||
|
0,*t*)
|
||||||
|
# Explicit resume command and we do not have file, so
|
||||||
|
# we are happy.
|
||||||
|
: ;;
|
||||||
|
0,)
|
||||||
|
# No file input but without resume parameters; catch
|
||||||
|
# user error to feed us a patch from standard input
|
||||||
|
# when there is already $dotest. This is somewhat
|
||||||
|
# unreliable -- stdin could be /dev/null for example
|
||||||
|
# and the caller did not intend to feed us a patch but
|
||||||
|
# wanted to continue unattended.
|
||||||
|
test -t 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
false
|
||||||
|
;;
|
||||||
|
esac ||
|
||||||
|
die "previous rebase directory $dotest still exists but mbox given."
|
||||||
|
resume=yes
|
||||||
|
|
||||||
|
case "$skip,$abort" in
|
||||||
|
t,t)
|
||||||
|
die "Please make up your mind. --skip or --abort?"
|
||||||
|
;;
|
||||||
|
t,)
|
||||||
|
git rerere clear
|
||||||
|
git read-tree --reset -u HEAD HEAD
|
||||||
|
orig_head=$(cat "$GIT_DIR/ORIG_HEAD")
|
||||||
|
git reset HEAD
|
||||||
|
git update-ref ORIG_HEAD $orig_head
|
||||||
|
;;
|
||||||
|
,t)
|
||||||
|
if test -f "$dotest/rebasing"
|
||||||
|
then
|
||||||
|
exec git rebase --abort
|
||||||
|
fi
|
||||||
|
git rerere clear
|
||||||
|
if safe_to_abort
|
||||||
|
then
|
||||||
|
git read-tree --reset -u HEAD ORIG_HEAD
|
||||||
|
git reset ORIG_HEAD
|
||||||
|
fi
|
||||||
|
rm -fr "$dotest"
|
||||||
|
exit ;;
|
||||||
|
esac
|
||||||
|
rm -f "$dotest/dirtyindex"
|
||||||
|
else
|
||||||
|
# Make sure we are not given --skip, --resolved, nor --abort
|
||||||
|
test "$skip$resolved$abort" = "" ||
|
||||||
|
die "Resolve operation not in progress, we are not resuming."
|
||||||
|
|
||||||
|
# Start afresh.
|
||||||
|
mkdir -p "$dotest" || exit
|
||||||
|
|
||||||
|
if test -n "$prefix" && test $# != 0
|
||||||
|
then
|
||||||
|
first=t
|
||||||
|
for arg
|
||||||
|
do
|
||||||
|
test -n "$first" && {
|
||||||
|
set x
|
||||||
|
first=
|
||||||
|
}
|
||||||
|
if is_absolute_path "$arg"
|
||||||
|
then
|
||||||
|
set "$@" "$arg"
|
||||||
|
else
|
||||||
|
set "$@" "$prefix$arg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_patch_format "$@"
|
||||||
|
|
||||||
|
split_patches "$@"
|
||||||
|
|
||||||
|
# -i can and must be given when resuming; everything
|
||||||
|
# else is kept
|
||||||
|
echo " $git_apply_opt" >"$dotest/apply-opt"
|
||||||
|
echo "$threeway" >"$dotest/threeway"
|
||||||
|
echo "$sign" >"$dotest/sign"
|
||||||
|
echo "$utf8" >"$dotest/utf8"
|
||||||
|
echo "$keep" >"$dotest/keep"
|
||||||
|
echo "$keepcr" >"$dotest/keepcr"
|
||||||
|
echo "$scissors" >"$dotest/scissors"
|
||||||
|
echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
|
||||||
|
echo "$GIT_QUIET" >"$dotest/quiet"
|
||||||
|
echo 1 >"$dotest/next"
|
||||||
|
if test -n "$rebasing"
|
||||||
|
then
|
||||||
|
: >"$dotest/rebasing"
|
||||||
|
else
|
||||||
|
: >"$dotest/applying"
|
||||||
|
if test -n "$HAS_HEAD"
|
||||||
|
then
|
||||||
|
git update-ref ORIG_HEAD HEAD
|
||||||
|
else
|
||||||
|
git update-ref -d ORIG_HEAD >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$resolved" in
|
||||||
|
'')
|
||||||
|
case "$HAS_HEAD" in
|
||||||
|
'')
|
||||||
|
files=$(git ls-files) ;;
|
||||||
|
?*)
|
||||||
|
files=$(git diff-index --cached --name-only HEAD --) ;;
|
||||||
|
esac || exit
|
||||||
|
if test "$files"
|
||||||
|
then
|
||||||
|
test -n "$HAS_HEAD" && : >"$dotest/dirtyindex"
|
||||||
|
die "Dirty index: cannot apply patches (dirty: $files)"
|
||||||
|
fi
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test "$(cat "$dotest/utf8")" = t
|
||||||
|
then
|
||||||
|
utf8=-u
|
||||||
|
else
|
||||||
|
utf8=-n
|
||||||
|
fi
|
||||||
|
if test "$(cat "$dotest/keep")" = t
|
||||||
|
then
|
||||||
|
keep=-k
|
||||||
|
fi
|
||||||
|
case "$(cat "$dotest/keepcr")" in
|
||||||
|
t)
|
||||||
|
keepcr=--keep-cr ;;
|
||||||
|
f)
|
||||||
|
keepcr=--no-keep-cr ;;
|
||||||
|
esac
|
||||||
|
case "$(cat "$dotest/scissors")" in
|
||||||
|
t)
|
||||||
|
scissors=--scissors ;;
|
||||||
|
f)
|
||||||
|
scissors=--no-scissors ;;
|
||||||
|
esac
|
||||||
|
if test "$(cat "$dotest/no_inbody_headers")" = t
|
||||||
|
then
|
||||||
|
no_inbody_headers=--no-inbody-headers
|
||||||
|
else
|
||||||
|
no_inbody_headers=
|
||||||
|
fi
|
||||||
|
if test "$(cat "$dotest/quiet")" = t
|
||||||
|
then
|
||||||
|
GIT_QUIET=t
|
||||||
|
fi
|
||||||
|
if test "$(cat "$dotest/threeway")" = t
|
||||||
|
then
|
||||||
|
threeway=t
|
||||||
|
fi
|
||||||
|
git_apply_opt=$(cat "$dotest/apply-opt")
|
||||||
|
if test "$(cat "$dotest/sign")" = t
|
||||||
|
then
|
||||||
|
SIGNOFF=`git var GIT_COMMITTER_IDENT | sed -e '
|
||||||
|
s/>.*/>/
|
||||||
|
s/^/Signed-off-by: /'
|
||||||
|
`
|
||||||
|
else
|
||||||
|
SIGNOFF=
|
||||||
|
fi
|
||||||
|
|
||||||
|
last=`cat "$dotest/last"`
|
||||||
|
this=`cat "$dotest/next"`
|
||||||
|
if test "$skip" = t
|
||||||
|
then
|
||||||
|
this=`expr "$this" + 1`
|
||||||
|
resume=
|
||||||
|
fi
|
||||||
|
|
||||||
|
while test "$this" -le "$last"
|
||||||
|
do
|
||||||
|
msgnum=`printf "%0${prec}d" $this`
|
||||||
|
next=`expr "$this" + 1`
|
||||||
|
test -f "$dotest/$msgnum" || {
|
||||||
|
resume=
|
||||||
|
go_next
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# If we are not resuming, parse and extract the patch information
|
||||||
|
# into separate files:
|
||||||
|
# - info records the authorship and title
|
||||||
|
# - msg is the rest of commit log message
|
||||||
|
# - patch is the patch body.
|
||||||
|
#
|
||||||
|
# When we are resuming, these files are either already prepared
|
||||||
|
# by the user, or the user can tell us to do so by --resolved flag.
|
||||||
|
case "$resume" in
|
||||||
|
'')
|
||||||
|
git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
|
||||||
|
<"$dotest/$msgnum" >"$dotest/info" ||
|
||||||
|
stop_here $this
|
||||||
|
|
||||||
|
# skip pine's internal folder data
|
||||||
|
sane_grep '^Author: Mail System Internal Data$' \
|
||||||
|
<"$dotest"/info >/dev/null &&
|
||||||
|
go_next && continue
|
||||||
|
|
||||||
|
test -s "$dotest/patch" || {
|
||||||
|
echo "Patch is empty. Was it split wrong?"
|
||||||
|
echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
|
||||||
|
echo "To restore the original branch and stop patching run \"$cmdline --abort\"."
|
||||||
|
stop_here $this
|
||||||
|
}
|
||||||
|
rm -f "$dotest/original-commit" "$dotest/author-script"
|
||||||
|
if test -f "$dotest/rebasing" &&
|
||||||
|
commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
|
||||||
|
-e q "$dotest/$msgnum") &&
|
||||||
|
test "$(git cat-file -t "$commit")" = commit
|
||||||
|
then
|
||||||
|
git cat-file commit "$commit" |
|
||||||
|
sed -e '1,/^$/d' >"$dotest/msg-clean"
|
||||||
|
echo "$commit" > "$dotest/original-commit"
|
||||||
|
get_author_ident_from_commit "$commit" > "$dotest/author-script"
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sed -n '/^Subject/ s/Subject: //p' "$dotest/info"
|
||||||
|
echo
|
||||||
|
cat "$dotest/msg"
|
||||||
|
} |
|
||||||
|
git stripspace > "$dotest/msg-clean"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test -f "$dotest/author-script"
|
||||||
|
then
|
||||||
|
eval $(cat "$dotest/author-script")
|
||||||
|
else
|
||||||
|
GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
|
||||||
|
GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
|
||||||
|
GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$GIT_AUTHOR_EMAIL"
|
||||||
|
then
|
||||||
|
echo "Patch does not have a valid e-mail address."
|
||||||
|
stop_here $this
|
||||||
|
fi
|
||||||
|
|
||||||
|
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
|
||||||
|
|
||||||
|
case "$resume" in
|
||||||
|
'')
|
||||||
|
if test '' != "$SIGNOFF"
|
||||||
|
then
|
||||||
|
LAST_SIGNED_OFF_BY=`
|
||||||
|
sed -ne '/^Signed-off-by: /p' \
|
||||||
|
"$dotest/msg-clean" |
|
||||||
|
sed -ne '$p'
|
||||||
|
`
|
||||||
|
ADD_SIGNOFF=`
|
||||||
|
test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
|
||||||
|
test '' = "$LAST_SIGNED_OFF_BY" && echo
|
||||||
|
echo "$SIGNOFF"
|
||||||
|
}`
|
||||||
|
else
|
||||||
|
ADD_SIGNOFF=
|
||||||
|
fi
|
||||||
|
{
|
||||||
|
if test -s "$dotest/msg-clean"
|
||||||
|
then
|
||||||
|
cat "$dotest/msg-clean"
|
||||||
|
fi
|
||||||
|
if test '' != "$ADD_SIGNOFF"
|
||||||
|
then
|
||||||
|
echo "$ADD_SIGNOFF"
|
||||||
|
fi
|
||||||
|
} >"$dotest/final-commit"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
case "$resolved$interactive" in
|
||||||
|
tt)
|
||||||
|
# This is used only for interactive view option.
|
||||||
|
git diff-index -p --cached HEAD -- >"$dotest/patch"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
esac
|
||||||
|
|
||||||
|
resume=
|
||||||
|
if test "$interactive" = t
|
||||||
|
then
|
||||||
|
test -t 0 ||
|
||||||
|
die "cannot be interactive without stdin connected to a terminal."
|
||||||
|
action=again
|
||||||
|
while test "$action" = again
|
||||||
|
do
|
||||||
|
echo "Commit Body is:"
|
||||||
|
echo "--------------------------"
|
||||||
|
cat "$dotest/final-commit"
|
||||||
|
echo "--------------------------"
|
||||||
|
printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
||||||
|
read reply
|
||||||
|
case "$reply" in
|
||||||
|
[yY]*) action=yes ;;
|
||||||
|
[aA]*) action=yes interactive= ;;
|
||||||
|
[nN]*) action=skip ;;
|
||||||
|
[eE]*) git_editor "$dotest/final-commit"
|
||||||
|
action=again ;;
|
||||||
|
[vV]*) action=again
|
||||||
|
git_pager "$dotest/patch" ;;
|
||||||
|
*) action=again ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
action=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "$dotest/final-commit"
|
||||||
|
then
|
||||||
|
FIRSTLINE=$(sed 1q "$dotest/final-commit")
|
||||||
|
else
|
||||||
|
FIRSTLINE=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $action = skip
|
||||||
|
then
|
||||||
|
go_next
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -x "$GIT_DIR"/hooks/applypatch-msg
|
||||||
|
then
|
||||||
|
"$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" ||
|
||||||
|
stop_here $this
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "Applying: $FIRSTLINE"
|
||||||
|
|
||||||
|
case "$resolved" in
|
||||||
|
'')
|
||||||
|
# When we are allowed to fall back to 3-way later, don't give
|
||||||
|
# false errors during the initial attempt.
|
||||||
|
squelch=
|
||||||
|
if test "$threeway" = t
|
||||||
|
then
|
||||||
|
squelch='>/dev/null 2>&1 '
|
||||||
|
fi
|
||||||
|
eval "git apply $squelch$git_apply_opt"' --index "$dotest/patch"'
|
||||||
|
apply_status=$?
|
||||||
|
;;
|
||||||
|
t)
|
||||||
|
# Resolved means the user did all the hard work, and
|
||||||
|
# we do not have to do any patch application. Just
|
||||||
|
# trust what the user has in the index file and the
|
||||||
|
# working tree.
|
||||||
|
resolved=
|
||||||
|
git diff-index --quiet --cached HEAD -- && {
|
||||||
|
echo "No changes - did you forget to use 'git add'?"
|
||||||
|
echo "If there is nothing left to stage, chances are that something else"
|
||||||
|
echo "already introduced the same changes; you might want to skip this patch."
|
||||||
|
stop_here_user_resolve $this
|
||||||
|
}
|
||||||
|
unmerged=$(git ls-files -u)
|
||||||
|
if test -n "$unmerged"
|
||||||
|
then
|
||||||
|
echo "You still have unmerged paths in your index"
|
||||||
|
echo "did you forget to use 'git add'?"
|
||||||
|
stop_here_user_resolve $this
|
||||||
|
fi
|
||||||
|
apply_status=0
|
||||||
|
git rerere
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test $apply_status != 0 && test "$threeway" = t
|
||||||
|
then
|
||||||
|
if (fall_back_3way)
|
||||||
|
then
|
||||||
|
# Applying the patch to an earlier tree and merging the
|
||||||
|
# result may have produced the same tree as ours.
|
||||||
|
git diff-index --quiet --cached HEAD -- && {
|
||||||
|
say No changes -- Patch already applied.
|
||||||
|
go_next
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
# clear apply_status -- we have successfully merged.
|
||||||
|
apply_status=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test $apply_status != 0
|
||||||
|
then
|
||||||
|
printf 'Patch failed at %s %s\n' "$msgnum" "$FIRSTLINE"
|
||||||
|
stop_here_user_resolve $this
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -x "$GIT_DIR"/hooks/pre-applypatch
|
||||||
|
then
|
||||||
|
"$GIT_DIR"/hooks/pre-applypatch || stop_here $this
|
||||||
|
fi
|
||||||
|
|
||||||
|
tree=$(git write-tree) &&
|
||||||
|
commit=$(
|
||||||
|
if test -n "$ignore_date"
|
||||||
|
then
|
||||||
|
GIT_AUTHOR_DATE=
|
||||||
|
fi
|
||||||
|
parent=$(git rev-parse --verify -q HEAD) ||
|
||||||
|
say >&2 "applying to an empty history"
|
||||||
|
|
||||||
|
if test -n "$committer_date_is_author_date"
|
||||||
|
then
|
||||||
|
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
|
||||||
|
export GIT_COMMITTER_DATE
|
||||||
|
fi &&
|
||||||
|
git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit"
|
||||||
|
) &&
|
||||||
|
git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
|
||||||
|
stop_here $this
|
||||||
|
|
||||||
|
if test -f "$dotest/original-commit"; then
|
||||||
|
echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -x "$GIT_DIR"/hooks/post-applypatch
|
||||||
|
then
|
||||||
|
"$GIT_DIR"/hooks/post-applypatch
|
||||||
|
fi
|
||||||
|
|
||||||
|
go_next
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -s "$dotest"/rewritten; then
|
||||||
|
git notes copy --for-rewrite=rebase < "$dotest"/rewritten
|
||||||
|
if test -x "$GIT_DIR"/hooks/post-rewrite; then
|
||||||
|
"$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -fr "$dotest"
|
||||||
|
git gc --auto
|
1
SparkleShare/Mac/git/libexec/git-core/git-annotate
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-annotate
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-apply
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-apply
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1135
SparkleShare/Mac/git/libexec/git-core/git-archimport
Executable file
1135
SparkleShare/Mac/git/libexec/git-core/git-archimport
Executable file
File diff suppressed because it is too large
Load diff
1
SparkleShare/Mac/git/libexec/git-core/git-archive
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-archive
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
457
SparkleShare/Mac/git/libexec/git-core/git-bisect
Executable file
457
SparkleShare/Mac/git/libexec/git-core/git-bisect
Executable file
|
@ -0,0 +1,457 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
|
||||||
|
LONG_USAGE='git bisect help
|
||||||
|
print this long help message.
|
||||||
|
git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
|
||||||
|
reset bisect state and start bisection.
|
||||||
|
git bisect bad [<rev>]
|
||||||
|
mark <rev> a known-bad revision.
|
||||||
|
git bisect good [<rev>...]
|
||||||
|
mark <rev>... known-good revisions.
|
||||||
|
git bisect skip [(<rev>|<range>)...]
|
||||||
|
mark <rev>... untestable revisions.
|
||||||
|
git bisect next
|
||||||
|
find next bisection to test and check it out.
|
||||||
|
git bisect reset [<commit>]
|
||||||
|
finish bisection search and go back to commit.
|
||||||
|
git bisect visualize
|
||||||
|
show bisect status in gitk.
|
||||||
|
git bisect replay <logfile>
|
||||||
|
replay bisection log.
|
||||||
|
git bisect log
|
||||||
|
show bisect log.
|
||||||
|
git bisect run <cmd>...
|
||||||
|
use <cmd>... to automatically bisect.
|
||||||
|
|
||||||
|
Please use "git help bisect" to get the full man page.'
|
||||||
|
|
||||||
|
OPTIONS_SPEC=
|
||||||
|
. git-sh-setup
|
||||||
|
require_work_tree
|
||||||
|
|
||||||
|
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
||||||
|
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
||||||
|
|
||||||
|
bisect_autostart() {
|
||||||
|
test -s "$GIT_DIR/BISECT_START" || {
|
||||||
|
echo >&2 'You need to start by "git bisect start"'
|
||||||
|
if test -t 0
|
||||||
|
then
|
||||||
|
echo >&2 -n 'Do you want me to do it for you [Y/n]? '
|
||||||
|
read yesno
|
||||||
|
case "$yesno" in
|
||||||
|
[Nn]*)
|
||||||
|
exit ;;
|
||||||
|
esac
|
||||||
|
bisect_start
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_start() {
|
||||||
|
#
|
||||||
|
# Verify HEAD.
|
||||||
|
#
|
||||||
|
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
|
||||||
|
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
|
||||||
|
die "Bad HEAD - I need a HEAD"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if we are bisecting.
|
||||||
|
#
|
||||||
|
start_head=''
|
||||||
|
if test -s "$GIT_DIR/BISECT_START"
|
||||||
|
then
|
||||||
|
# Reset to the rev from where we started.
|
||||||
|
start_head=$(cat "$GIT_DIR/BISECT_START")
|
||||||
|
git checkout "$start_head" -- || exit
|
||||||
|
else
|
||||||
|
# Get rev from where we start.
|
||||||
|
case "$head" in
|
||||||
|
refs/heads/*|$_x40)
|
||||||
|
# This error message should only be triggered by
|
||||||
|
# cogito usage, and cogito users should understand
|
||||||
|
# it relates to cg-seek.
|
||||||
|
[ -s "$GIT_DIR/head-name" ] &&
|
||||||
|
die "won't bisect on seeked tree"
|
||||||
|
start_head="${head#refs/heads/}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Bad HEAD - strange symbolic ref"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get rid of any old bisect state.
|
||||||
|
#
|
||||||
|
bisect_clean_state || exit
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for one bad and then some good revisions.
|
||||||
|
#
|
||||||
|
has_double_dash=0
|
||||||
|
for arg; do
|
||||||
|
case "$arg" in --) has_double_dash=1; break ;; esac
|
||||||
|
done
|
||||||
|
orig_args=$(git rev-parse --sq-quote "$@")
|
||||||
|
bad_seen=0
|
||||||
|
eval=''
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
arg="$1"
|
||||||
|
case "$arg" in
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
rev=$(git rev-parse -q --verify "$arg^{commit}") || {
|
||||||
|
test $has_double_dash -eq 1 &&
|
||||||
|
die "'$arg' does not appear to be a valid revision"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case $bad_seen in
|
||||||
|
0) state='bad' ; bad_seen=1 ;;
|
||||||
|
*) state='good' ;;
|
||||||
|
esac
|
||||||
|
eval="$eval bisect_write '$state' '$rev' 'nolog'; "
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
#
|
||||||
|
# Change state.
|
||||||
|
# In case of mistaken revs or checkout error, or signals received,
|
||||||
|
# "bisect_auto_next" below may exit or misbehave.
|
||||||
|
# We have to trap this to be able to clean up using
|
||||||
|
# "bisect_clean_state".
|
||||||
|
#
|
||||||
|
trap 'bisect_clean_state' 0
|
||||||
|
trap 'exit 255' 1 2 3 15
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write new start state.
|
||||||
|
#
|
||||||
|
echo "$start_head" >"$GIT_DIR/BISECT_START" &&
|
||||||
|
git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
|
||||||
|
eval "$eval" &&
|
||||||
|
echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
|
||||||
|
#
|
||||||
|
# Check if we can proceed to the next bisect state.
|
||||||
|
#
|
||||||
|
bisect_auto_next
|
||||||
|
|
||||||
|
trap '-' 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_write() {
|
||||||
|
state="$1"
|
||||||
|
rev="$2"
|
||||||
|
nolog="$3"
|
||||||
|
case "$state" in
|
||||||
|
bad) tag="$state" ;;
|
||||||
|
good|skip) tag="$state"-"$rev" ;;
|
||||||
|
*) die "Bad bisect_write argument: $state" ;;
|
||||||
|
esac
|
||||||
|
git update-ref "refs/bisect/$tag" "$rev" || exit
|
||||||
|
echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
|
||||||
|
test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_expected_rev() {
|
||||||
|
test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
|
||||||
|
test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
|
||||||
|
}
|
||||||
|
|
||||||
|
check_expected_revs() {
|
||||||
|
for _rev in "$@"; do
|
||||||
|
if ! is_expected_rev "$_rev"; then
|
||||||
|
rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
|
||||||
|
rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_skip() {
|
||||||
|
all=''
|
||||||
|
for arg in "$@"
|
||||||
|
do
|
||||||
|
case "$arg" in
|
||||||
|
*..*)
|
||||||
|
revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
|
||||||
|
*)
|
||||||
|
revs=$(git rev-parse --sq-quote "$arg") ;;
|
||||||
|
esac
|
||||||
|
all="$all $revs"
|
||||||
|
done
|
||||||
|
eval bisect_state 'skip' $all
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_state() {
|
||||||
|
bisect_autostart
|
||||||
|
state=$1
|
||||||
|
case "$#,$state" in
|
||||||
|
0,*)
|
||||||
|
die "Please call 'bisect_state' with at least one argument." ;;
|
||||||
|
1,bad|1,good|1,skip)
|
||||||
|
rev=$(git rev-parse --verify HEAD) ||
|
||||||
|
die "Bad rev input: HEAD"
|
||||||
|
bisect_write "$state" "$rev"
|
||||||
|
check_expected_revs "$rev" ;;
|
||||||
|
2,bad|*,good|*,skip)
|
||||||
|
shift
|
||||||
|
eval=''
|
||||||
|
for rev in "$@"
|
||||||
|
do
|
||||||
|
sha=$(git rev-parse --verify "$rev^{commit}") ||
|
||||||
|
die "Bad rev input: $rev"
|
||||||
|
eval="$eval bisect_write '$state' '$sha'; "
|
||||||
|
done
|
||||||
|
eval "$eval"
|
||||||
|
check_expected_revs "$@" ;;
|
||||||
|
*,bad)
|
||||||
|
die "'git bisect bad' can take only one argument." ;;
|
||||||
|
*)
|
||||||
|
usage ;;
|
||||||
|
esac
|
||||||
|
bisect_auto_next
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_next_check() {
|
||||||
|
missing_good= missing_bad=
|
||||||
|
git show-ref -q --verify refs/bisect/bad || missing_bad=t
|
||||||
|
test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
|
||||||
|
|
||||||
|
case "$missing_good,$missing_bad,$1" in
|
||||||
|
,,*)
|
||||||
|
: have both good and bad - ok
|
||||||
|
;;
|
||||||
|
*,)
|
||||||
|
# do not have both but not asked to fail - just report.
|
||||||
|
false
|
||||||
|
;;
|
||||||
|
t,,good)
|
||||||
|
# have bad but not good. we could bisect although
|
||||||
|
# this is less optimum.
|
||||||
|
echo >&2 'Warning: bisecting only with a bad commit.'
|
||||||
|
if test -t 0
|
||||||
|
then
|
||||||
|
printf >&2 'Are you sure [Y/n]? '
|
||||||
|
read yesno
|
||||||
|
case "$yesno" in [Nn]*) exit 1 ;; esac
|
||||||
|
fi
|
||||||
|
: bisect without good...
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
THEN=''
|
||||||
|
test -s "$GIT_DIR/BISECT_START" || {
|
||||||
|
echo >&2 'You need to start by "git bisect start".'
|
||||||
|
THEN='then '
|
||||||
|
}
|
||||||
|
echo >&2 'You '$THEN'need to give me at least one good' \
|
||||||
|
'and one bad revisions.'
|
||||||
|
echo >&2 '(You can use "git bisect bad" and' \
|
||||||
|
'"git bisect good" for that.)'
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_auto_next() {
|
||||||
|
bisect_next_check && bisect_next || :
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_next() {
|
||||||
|
case "$#" in 0) ;; *) usage ;; esac
|
||||||
|
bisect_autostart
|
||||||
|
bisect_next_check good
|
||||||
|
|
||||||
|
# Perform all bisection computation, display and checkout
|
||||||
|
git bisect--helper --next-all
|
||||||
|
res=$?
|
||||||
|
|
||||||
|
# Check if we should exit because bisection is finished
|
||||||
|
test $res -eq 10 && exit 0
|
||||||
|
|
||||||
|
# Check for an error in the bisection process
|
||||||
|
test $res -ne 0 && exit $res
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_visualize() {
|
||||||
|
bisect_next_check fail
|
||||||
|
|
||||||
|
if test $# = 0
|
||||||
|
then
|
||||||
|
case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
|
||||||
|
'') set git log ;;
|
||||||
|
set*) set gitk ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case "$1" in
|
||||||
|
git*|tig) ;;
|
||||||
|
-*) set git log "$@" ;;
|
||||||
|
*) set git "$@" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_reset() {
|
||||||
|
test -s "$GIT_DIR/BISECT_START" || {
|
||||||
|
echo "We are not bisecting."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "$#" in
|
||||||
|
0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
|
||||||
|
1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null ||
|
||||||
|
die "'$1' is not a valid commit"
|
||||||
|
branch="$1" ;;
|
||||||
|
*)
|
||||||
|
usage ;;
|
||||||
|
esac
|
||||||
|
if git checkout "$branch" -- ; then
|
||||||
|
bisect_clean_state
|
||||||
|
else
|
||||||
|
die "Could not check out original HEAD '$branch'." \
|
||||||
|
"Try 'git bisect reset <commit>'."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_clean_state() {
|
||||||
|
# There may be some refs packed during bisection.
|
||||||
|
git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
|
||||||
|
while read ref hash
|
||||||
|
do
|
||||||
|
git update-ref -d $ref $hash || exit
|
||||||
|
done
|
||||||
|
rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
|
||||||
|
rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
|
||||||
|
rm -f "$GIT_DIR/BISECT_LOG" &&
|
||||||
|
rm -f "$GIT_DIR/BISECT_NAMES" &&
|
||||||
|
rm -f "$GIT_DIR/BISECT_RUN" &&
|
||||||
|
# Cleanup head-name if it got left by an old version of git-bisect
|
||||||
|
rm -f "$GIT_DIR/head-name" &&
|
||||||
|
|
||||||
|
rm -f "$GIT_DIR/BISECT_START"
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_replay () {
|
||||||
|
test "$#" -eq 1 || die "No logfile given"
|
||||||
|
test -r "$1" || die "cannot read $1 for replaying"
|
||||||
|
bisect_reset
|
||||||
|
while read git bisect command rev
|
||||||
|
do
|
||||||
|
test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
|
||||||
|
if test "$git" = "git-bisect"; then
|
||||||
|
rev="$command"
|
||||||
|
command="$bisect"
|
||||||
|
fi
|
||||||
|
case "$command" in
|
||||||
|
start)
|
||||||
|
cmd="bisect_start $rev"
|
||||||
|
eval "$cmd" ;;
|
||||||
|
good|bad|skip)
|
||||||
|
bisect_write "$command" "$rev" ;;
|
||||||
|
*)
|
||||||
|
die "?? what are you talking about?" ;;
|
||||||
|
esac
|
||||||
|
done <"$1"
|
||||||
|
bisect_auto_next
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_run () {
|
||||||
|
bisect_next_check fail
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
echo "running $@"
|
||||||
|
"$@"
|
||||||
|
res=$?
|
||||||
|
|
||||||
|
# Check for really bad run error.
|
||||||
|
if [ $res -lt 0 -o $res -ge 128 ]; then
|
||||||
|
echo >&2 "bisect run failed:"
|
||||||
|
echo >&2 "exit code $res from '$@' is < 0 or >= 128"
|
||||||
|
exit $res
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find current state depending on run success or failure.
|
||||||
|
# A special exit code of 125 means cannot test.
|
||||||
|
if [ $res -eq 125 ]; then
|
||||||
|
state='skip'
|
||||||
|
elif [ $res -gt 0 ]; then
|
||||||
|
state='bad'
|
||||||
|
else
|
||||||
|
state='good'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We have to use a subshell because "bisect_state" can exit.
|
||||||
|
( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
|
||||||
|
res=$?
|
||||||
|
|
||||||
|
cat "$GIT_DIR/BISECT_RUN"
|
||||||
|
|
||||||
|
if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
|
||||||
|
> /dev/null; then
|
||||||
|
echo >&2 "bisect run cannot continue any more"
|
||||||
|
exit $res
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $res -ne 0 ]; then
|
||||||
|
echo >&2 "bisect run failed:"
|
||||||
|
echo >&2 "'bisect_state $state' exited with error code $res"
|
||||||
|
exit $res
|
||||||
|
fi
|
||||||
|
|
||||||
|
if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
|
||||||
|
echo "bisect run success"
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
bisect_log () {
|
||||||
|
test -s "$GIT_DIR/BISECT_LOG" || die "We are not bisecting."
|
||||||
|
cat "$GIT_DIR/BISECT_LOG"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$#" in
|
||||||
|
0)
|
||||||
|
usage ;;
|
||||||
|
*)
|
||||||
|
cmd="$1"
|
||||||
|
shift
|
||||||
|
case "$cmd" in
|
||||||
|
help)
|
||||||
|
git bisect -h ;;
|
||||||
|
start)
|
||||||
|
bisect_start "$@" ;;
|
||||||
|
bad|good)
|
||||||
|
bisect_state "$cmd" "$@" ;;
|
||||||
|
skip)
|
||||||
|
bisect_skip "$@" ;;
|
||||||
|
next)
|
||||||
|
# Not sure we want "next" at the UI level anymore.
|
||||||
|
bisect_next "$@" ;;
|
||||||
|
visualize|view)
|
||||||
|
bisect_visualize "$@" ;;
|
||||||
|
reset)
|
||||||
|
bisect_reset "$@" ;;
|
||||||
|
replay)
|
||||||
|
bisect_replay "$@" ;;
|
||||||
|
log)
|
||||||
|
bisect_log ;;
|
||||||
|
run)
|
||||||
|
bisect_run "$@" ;;
|
||||||
|
*)
|
||||||
|
usage ;;
|
||||||
|
esac
|
||||||
|
esac
|
1
SparkleShare/Mac/git/libexec/git-core/git-bisect--helper
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-bisect--helper
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-blame
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-blame
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-branch
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-branch
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-bundle
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-bundle
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-cat-file
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-cat-file
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-check-attr
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-check-attr
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-check-ref-format
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-check-ref-format
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-checkout
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-checkout
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-checkout-index
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-checkout-index
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-cherry
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-cherry
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-cherry-pick
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-cherry-pick
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
8
SparkleShare/Mac/git/libexec/git-core/git-citool
Executable file
8
SparkleShare/Mac/git/libexec/git-core/git-citool
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
if test "z$*" = zversion ||
|
||||||
|
test "z$*" = z--version
|
||||||
|
then
|
||||||
|
echo 'git-gui version 0.13.0.8.g8f85'
|
||||||
|
else
|
||||||
|
exec '/usr/local/git/share/git-gui/lib/Git Gui.app/Contents/MacOS/Wish' "$0" "$@"
|
||||||
|
fi
|
1
SparkleShare/Mac/git/libexec/git-core/git-clean
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-clean
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-clone
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-clone
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-commit
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-commit
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-commit-tree
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-commit-tree
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-config
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-config
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-count-objects
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-count-objects
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
456
SparkleShare/Mac/git/libexec/git-core/git-cvsexportcommit
Executable file
456
SparkleShare/Mac/git/libexec/git-core/git-cvsexportcommit
Executable file
|
@ -0,0 +1,456 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
use lib (split(/:/, $ENV{GITPERLLIB} || "/usr/local/git/lib/perl5/site_perl"));
|
||||||
|
|
||||||
|
use 5.008;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Getopt::Std;
|
||||||
|
use File::Temp qw(tempdir);
|
||||||
|
use Data::Dumper;
|
||||||
|
use File::Basename qw(basename dirname);
|
||||||
|
use File::Spec;
|
||||||
|
use Git;
|
||||||
|
|
||||||
|
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w, $opt_W, $opt_k);
|
||||||
|
|
||||||
|
getopts('uhPpvcfkam:d:w:W');
|
||||||
|
|
||||||
|
$opt_h && usage();
|
||||||
|
|
||||||
|
die "Need at least one commit identifier!" unless @ARGV;
|
||||||
|
|
||||||
|
# Get git-config settings
|
||||||
|
my $repo = Git->repository();
|
||||||
|
$opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
|
||||||
|
|
||||||
|
if ($opt_w || $opt_W) {
|
||||||
|
# Remember where GIT_DIR is before changing to CVS checkout
|
||||||
|
unless ($ENV{GIT_DIR}) {
|
||||||
|
# No GIT_DIR set. Figure it out for ourselves
|
||||||
|
my $gd =`git-rev-parse --git-dir`;
|
||||||
|
chomp($gd);
|
||||||
|
$ENV{GIT_DIR} = $gd;
|
||||||
|
}
|
||||||
|
# Make sure GIT_DIR is absolute
|
||||||
|
$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_w) {
|
||||||
|
if (! -d $opt_w."/CVS" ) {
|
||||||
|
die "$opt_w is not a CVS checkout";
|
||||||
|
}
|
||||||
|
chdir $opt_w or die "Cannot change to CVS checkout at $opt_w";
|
||||||
|
}
|
||||||
|
unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
|
||||||
|
die "GIT_DIR is not defined or is unreadable";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my @cvs;
|
||||||
|
if ($opt_d) {
|
||||||
|
@cvs = ('cvs', '-d', $opt_d);
|
||||||
|
} else {
|
||||||
|
@cvs = ('cvs');
|
||||||
|
}
|
||||||
|
|
||||||
|
# resolve target commit
|
||||||
|
my $commit;
|
||||||
|
$commit = pop @ARGV;
|
||||||
|
$commit = safe_pipe_capture('git-rev-parse', '--verify', "$commit^0");
|
||||||
|
chomp $commit;
|
||||||
|
if ($?) {
|
||||||
|
die "The commit reference $commit did not resolve!";
|
||||||
|
}
|
||||||
|
|
||||||
|
# resolve what parent we want
|
||||||
|
my $parent;
|
||||||
|
if (@ARGV) {
|
||||||
|
$parent = pop @ARGV;
|
||||||
|
$parent = safe_pipe_capture('git-rev-parse', '--verify', "$parent^0");
|
||||||
|
chomp $parent;
|
||||||
|
if ($?) {
|
||||||
|
die "The parent reference did not resolve!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# find parents from the commit itself
|
||||||
|
my @commit = safe_pipe_capture('git-cat-file', 'commit', $commit);
|
||||||
|
my @parents;
|
||||||
|
my $committer;
|
||||||
|
my $author;
|
||||||
|
my $stage = 'headers'; # headers, msg
|
||||||
|
my $title;
|
||||||
|
my $msg = '';
|
||||||
|
|
||||||
|
foreach my $line (@commit) {
|
||||||
|
chomp $line;
|
||||||
|
if ($stage eq 'headers' && $line eq '') {
|
||||||
|
$stage = 'msg';
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stage eq 'headers') {
|
||||||
|
if ($line =~ m/^parent (\w{40})$/) { # found a parent
|
||||||
|
push @parents, $1;
|
||||||
|
} elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
|
||||||
|
$author = $1;
|
||||||
|
} elsif ($line =~ m/^committer (.+) \d+ [-+]\d+$/) {
|
||||||
|
$committer = $1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$msg .= $line . "\n";
|
||||||
|
unless ($title) {
|
||||||
|
$title = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $noparent = "0000000000000000000000000000000000000000";
|
||||||
|
if ($parent) {
|
||||||
|
my $found;
|
||||||
|
# double check that it's a valid parent
|
||||||
|
foreach my $p (@parents) {
|
||||||
|
if ($p eq $parent) {
|
||||||
|
$found = 1;
|
||||||
|
last;
|
||||||
|
}; # found it
|
||||||
|
}
|
||||||
|
die "Did not find $parent in the parents for this commit!" if !$found and !$opt_P;
|
||||||
|
} else { # we don't have a parent from the cmdline...
|
||||||
|
if (@parents == 1) { # it's safe to get it from the commit
|
||||||
|
$parent = $parents[0];
|
||||||
|
} elsif (@parents == 0) { # there is no parent
|
||||||
|
$parent = $noparent;
|
||||||
|
} else { # cannot choose automatically from multiple parents
|
||||||
|
die "This commit has more than one parent -- please name the parent you want to use explicitly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $go_back_to = 0;
|
||||||
|
|
||||||
|
if ($opt_W) {
|
||||||
|
$opt_v && print "Resetting to $parent\n";
|
||||||
|
$go_back_to = `git symbolic-ref HEAD 2> /dev/null ||
|
||||||
|
git rev-parse HEAD` || die "Could not determine current branch";
|
||||||
|
system("git checkout -q $parent^0") && die "Could not check out $parent^0";
|
||||||
|
}
|
||||||
|
|
||||||
|
$opt_v && print "Applying to CVS commit $commit from parent $parent\n";
|
||||||
|
|
||||||
|
# grab the commit message
|
||||||
|
open(MSG, ">.msg") or die "Cannot open .msg for writing";
|
||||||
|
if ($opt_m) {
|
||||||
|
print MSG $opt_m;
|
||||||
|
}
|
||||||
|
print MSG $msg;
|
||||||
|
if ($opt_a) {
|
||||||
|
print MSG "\n\nAuthor: $author\n";
|
||||||
|
if ($author ne $committer) {
|
||||||
|
print MSG "Committer: $committer\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close MSG;
|
||||||
|
|
||||||
|
if ($parent eq $noparent) {
|
||||||
|
`git-diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
|
||||||
|
} else {
|
||||||
|
`git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
|
||||||
|
}
|
||||||
|
|
||||||
|
## apply non-binary changes
|
||||||
|
|
||||||
|
# In pedantic mode require all lines of context to match. In normal
|
||||||
|
# mode, be compatible with diff/patch: assume 3 lines of context and
|
||||||
|
# require at least one line match, i.e. ignore at most 2 lines of
|
||||||
|
# context, like diff/patch do by default.
|
||||||
|
my $context = $opt_p ? '' : '-C1';
|
||||||
|
|
||||||
|
print "Checking if patch will apply\n";
|
||||||
|
|
||||||
|
my @stat;
|
||||||
|
open APPLY, "GIT_DIR= git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
|
||||||
|
@stat=<APPLY>;
|
||||||
|
close APPLY || die "Cannot patch";
|
||||||
|
my (@bfiles,@files,@afiles,@dfiles);
|
||||||
|
chomp @stat;
|
||||||
|
foreach (@stat) {
|
||||||
|
push (@bfiles,$1) if m/^-\t-\t(.*)$/;
|
||||||
|
push (@files, $1) if m/^-\t-\t(.*)$/;
|
||||||
|
push (@files, $1) if m/^\d+\t\d+\t(.*)$/;
|
||||||
|
push (@afiles,$1) if m/^ create mode [0-7]+ (.*)$/;
|
||||||
|
push (@dfiles,$1) if m/^ delete mode [0-7]+ (.*)$/;
|
||||||
|
}
|
||||||
|
map { s/^"(.*)"$/$1/g } @bfiles,@files;
|
||||||
|
map { s/\\([0-7]{3})/sprintf('%c',oct $1)/eg } @bfiles,@files;
|
||||||
|
|
||||||
|
# check that the files are clean and up to date according to cvs
|
||||||
|
my $dirty;
|
||||||
|
my @dirs;
|
||||||
|
foreach my $p (@afiles) {
|
||||||
|
my $path = dirname $p;
|
||||||
|
while (!-d $path and ! grep { $_ eq $path } @dirs) {
|
||||||
|
unshift @dirs, $path;
|
||||||
|
$path = dirname $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... check dirs,
|
||||||
|
foreach my $d (@dirs) {
|
||||||
|
if (-e $d) {
|
||||||
|
$dirty = 1;
|
||||||
|
warn "$d exists and is not a directory!\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... query status of all files that we have a directory for and parse output of 'cvs status' to %cvsstat.
|
||||||
|
my @canstatusfiles;
|
||||||
|
foreach my $f (@files) {
|
||||||
|
my $path = dirname $f;
|
||||||
|
next if (grep { $_ eq $path } @dirs);
|
||||||
|
push @canstatusfiles, $f;
|
||||||
|
}
|
||||||
|
|
||||||
|
my %cvsstat;
|
||||||
|
if (@canstatusfiles) {
|
||||||
|
if ($opt_u) {
|
||||||
|
my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles);
|
||||||
|
print @updated;
|
||||||
|
}
|
||||||
|
# "cvs status" reorders the parameters, notably when there are multiple
|
||||||
|
# arguments with the same basename. So be precise here.
|
||||||
|
|
||||||
|
my %added = map { $_ => 1 } @afiles;
|
||||||
|
my %todo = map { $_ => 1 } @canstatusfiles;
|
||||||
|
|
||||||
|
while (%todo) {
|
||||||
|
my @canstatusfiles2 = ();
|
||||||
|
my %fullname = ();
|
||||||
|
foreach my $name (keys %todo) {
|
||||||
|
my $basename = basename($name);
|
||||||
|
|
||||||
|
# CVS reports files that don't exist in the current revision as
|
||||||
|
# "no file $basename" in its "status" output, so we should
|
||||||
|
# anticipate that. Totally unknown files will have a status
|
||||||
|
# "Unknown". However, if they exist in the Attic, their status
|
||||||
|
# will be "Up-to-date" (this means they were added once but have
|
||||||
|
# been removed).
|
||||||
|
$basename = "no file $basename" if $added{$basename};
|
||||||
|
|
||||||
|
$basename =~ s/^\s+//;
|
||||||
|
$basename =~ s/\s+$//;
|
||||||
|
|
||||||
|
if (!exists($fullname{$basename})) {
|
||||||
|
$fullname{$basename} = $name;
|
||||||
|
push (@canstatusfiles2, $name);
|
||||||
|
delete($todo{$name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my @cvsoutput;
|
||||||
|
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles2);
|
||||||
|
foreach my $l (@cvsoutput) {
|
||||||
|
chomp $l;
|
||||||
|
next unless
|
||||||
|
my ($file, $status) = $l =~ /^File:\s+(.*\S)\s+Status: (.*)$/;
|
||||||
|
|
||||||
|
my $fullname = $fullname{$file};
|
||||||
|
print STDERR "Huh? Status '$status' reported for unexpected file '$file'\n"
|
||||||
|
unless defined $fullname;
|
||||||
|
|
||||||
|
# This response means the file does not exist except in
|
||||||
|
# CVS's attic, so set the status accordingly
|
||||||
|
$status = "In-attic"
|
||||||
|
if $file =~ /^no file /
|
||||||
|
&& $status eq 'Up-to-date';
|
||||||
|
|
||||||
|
$cvsstat{$fullname{$file}} = $status
|
||||||
|
if defined $fullname{$file};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... Validate that new files have the correct status
|
||||||
|
foreach my $f (@afiles) {
|
||||||
|
next unless defined(my $stat = $cvsstat{$f});
|
||||||
|
|
||||||
|
# This means the file has never been seen before
|
||||||
|
next if $stat eq 'Unknown';
|
||||||
|
|
||||||
|
# This means the file has been seen before but was removed
|
||||||
|
next if $stat eq 'In-attic';
|
||||||
|
|
||||||
|
$dirty = 1;
|
||||||
|
warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n";
|
||||||
|
warn "Status was: $cvsstat{$f}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... validate known files.
|
||||||
|
foreach my $f (@files) {
|
||||||
|
next if grep { $_ eq $f } @afiles;
|
||||||
|
# TODO:we need to handle removed in cvs
|
||||||
|
unless (defined ($cvsstat{$f}) and $cvsstat{$f} eq "Up-to-date") {
|
||||||
|
$dirty = 1;
|
||||||
|
warn "File $f not up to date but has status '$cvsstat{$f}' in your CVS checkout!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Depending on how your GIT tree got imported from CVS you may
|
||||||
|
# have a conflict between expanded keywords in your CVS tree and
|
||||||
|
# unexpanded keywords in the patch about to be applied.
|
||||||
|
if ($opt_k) {
|
||||||
|
my $orig_file ="$f.orig";
|
||||||
|
rename $f, $orig_file;
|
||||||
|
open(FILTER_IN, "<$orig_file") or die "Cannot open $orig_file\n";
|
||||||
|
open(FILTER_OUT, ">$f") or die "Cannot open $f\n";
|
||||||
|
while (<FILTER_IN>)
|
||||||
|
{
|
||||||
|
my $line = $_;
|
||||||
|
$line =~ s/\$([A-Z][a-z]+):[^\$]+\$/\$$1\$/g;
|
||||||
|
print FILTER_OUT $line;
|
||||||
|
}
|
||||||
|
close FILTER_IN;
|
||||||
|
close FILTER_OUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dirty) {
|
||||||
|
if ($opt_f) { warn "The tree is not clean -- forced merge\n";
|
||||||
|
$dirty = 0;
|
||||||
|
} else {
|
||||||
|
die "Exiting: your CVS tree is not clean for this merge.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Applying\n";
|
||||||
|
if ($opt_W) {
|
||||||
|
system("git checkout -q $commit^0") && die "cannot patch";
|
||||||
|
} else {
|
||||||
|
`GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Patch applied successfully. Adding new files and directories to CVS\n";
|
||||||
|
my $dirtypatch = 0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# We have to add the directories in order otherwise we will have
|
||||||
|
# problems when we try and add the sub-directory of a directory we
|
||||||
|
# have not added yet.
|
||||||
|
#
|
||||||
|
# Luckily this is easy to deal with by sorting the directories and
|
||||||
|
# dealing with the shortest ones first.
|
||||||
|
#
|
||||||
|
@dirs = sort { length $a <=> length $b} @dirs;
|
||||||
|
|
||||||
|
foreach my $d (@dirs) {
|
||||||
|
if (system(@cvs,'add',$d)) {
|
||||||
|
$dirtypatch = 1;
|
||||||
|
warn "Failed to cvs add directory $d -- you may need to do it manually";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $f (@afiles) {
|
||||||
|
if (grep { $_ eq $f } @bfiles) {
|
||||||
|
system(@cvs, 'add','-kb',$f);
|
||||||
|
} else {
|
||||||
|
system(@cvs, 'add', $f);
|
||||||
|
}
|
||||||
|
if ($?) {
|
||||||
|
$dirtypatch = 1;
|
||||||
|
warn "Failed to cvs add $f -- you may need to do it manually";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $f (@dfiles) {
|
||||||
|
system(@cvs, 'rm', '-f', $f);
|
||||||
|
if ($?) {
|
||||||
|
$dirtypatch = 1;
|
||||||
|
warn "Failed to cvs rm -f $f -- you may need to do it manually";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Commit to CVS\n";
|
||||||
|
print "Patch title (first comment line): $title\n";
|
||||||
|
my @commitfiles = map { unless (m/\s/) { '\''.$_.'\''; } else { $_; }; } (@files);
|
||||||
|
my $cmd = join(' ', @cvs)." commit -F .msg @commitfiles";
|
||||||
|
|
||||||
|
if ($dirtypatch) {
|
||||||
|
print "NOTE: One or more hunks failed to apply cleanly.\n";
|
||||||
|
print "You'll need to apply the patch in .cvsexportcommit.diff manually\n";
|
||||||
|
print "using a patch program. After applying the patch and resolving the\n";
|
||||||
|
print "problems you may commit using:";
|
||||||
|
print "\n cd \"$opt_w\"" if $opt_w;
|
||||||
|
print "\n $cmd\n";
|
||||||
|
print "\n git checkout $go_back_to\n" if $go_back_to;
|
||||||
|
print "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_c) {
|
||||||
|
print "Autocommit\n $cmd\n";
|
||||||
|
print xargs_safe_pipe_capture([@cvs, 'commit', '-F', '.msg'], @files);
|
||||||
|
if ($?) {
|
||||||
|
die "Exiting: The commit did not succeed";
|
||||||
|
}
|
||||||
|
print "Committed successfully to CVS\n";
|
||||||
|
# clean up
|
||||||
|
unlink(".msg");
|
||||||
|
} else {
|
||||||
|
print "Ready for you to commit, just run:\n\n $cmd\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# clean up
|
||||||
|
unlink(".cvsexportcommit.diff");
|
||||||
|
|
||||||
|
if ($opt_W) {
|
||||||
|
system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
|
||||||
|
if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
|
||||||
|
system("git symbolic-ref HEAD $go_back_to") &&
|
||||||
|
die "cannot move back to $go_back_to";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# CVS version 1.11.x and 1.12.x sleeps the wrong way to ensure the timestamp
|
||||||
|
# used by CVS and the one set by subsequence file modifications are different.
|
||||||
|
# If they are not different CVS will not detect changes.
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
sub usage {
|
||||||
|
print STDERR <<END;
|
||||||
|
Usage: GIT_DIR=/path/to/.git git cvsexportcommit [-h] [-p] [-v] [-c] [-f] [-u] [-k] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
|
||||||
|
END
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
# An alternative to `command` that allows input to be passed as an array
|
||||||
|
# to work around shell problems with weird characters in arguments
|
||||||
|
# if the exec returns non-zero we die
|
||||||
|
sub safe_pipe_capture {
|
||||||
|
my @output;
|
||||||
|
if (my $pid = open my $child, '-|') {
|
||||||
|
@output = (<$child>);
|
||||||
|
close $child or die join(' ',@_).": $! $?";
|
||||||
|
} else {
|
||||||
|
exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
|
||||||
|
}
|
||||||
|
return wantarray ? @output : join('',@output);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub xargs_safe_pipe_capture {
|
||||||
|
my $MAX_ARG_LENGTH = 65536;
|
||||||
|
my $cmd = shift;
|
||||||
|
my @output;
|
||||||
|
my $output;
|
||||||
|
while(@_) {
|
||||||
|
my @args;
|
||||||
|
my $length = 0;
|
||||||
|
while(@_ && $length < $MAX_ARG_LENGTH) {
|
||||||
|
push @args, shift;
|
||||||
|
$length += length($args[$#args]);
|
||||||
|
}
|
||||||
|
if (wantarray) {
|
||||||
|
push @output, safe_pipe_capture(@$cmd, @args);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$output .= safe_pipe_capture(@$cmd, @args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wantarray ? @output : $output;
|
||||||
|
}
|
1097
SparkleShare/Mac/git/libexec/git-core/git-cvsimport
Executable file
1097
SparkleShare/Mac/git/libexec/git-core/git-cvsimport
Executable file
File diff suppressed because it is too large
Load diff
3696
SparkleShare/Mac/git/libexec/git-core/git-cvsserver
Executable file
3696
SparkleShare/Mac/git/libexec/git-core/git-cvsserver
Executable file
File diff suppressed because it is too large
Load diff
BIN
SparkleShare/Mac/git/libexec/git-core/git-daemon
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-daemon
Executable file
Binary file not shown.
1
SparkleShare/Mac/git/libexec/git-core/git-describe
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-describe
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-diff
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-diff
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-diff-files
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-diff-files
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-diff-index
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-diff-index
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-diff-tree
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-diff-tree
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
122
SparkleShare/Mac/git/libexec/git-core/git-difftool
Executable file
122
SparkleShare/Mac/git/libexec/git-core/git-difftool
Executable file
|
@ -0,0 +1,122 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
use lib (split(/:/, $ENV{GITPERLLIB} || "/usr/local/git/lib/perl5/site_perl"));
|
||||||
|
# Copyright (c) 2009, 2010 David Aguilar
|
||||||
|
#
|
||||||
|
# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
|
||||||
|
# git-difftool--helper script.
|
||||||
|
#
|
||||||
|
# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
|
||||||
|
# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL
|
||||||
|
# are exported for use by git-difftool--helper.
|
||||||
|
#
|
||||||
|
# Any arguments that are unknown to this script are forwarded to 'git diff'.
|
||||||
|
|
||||||
|
use 5.008;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Cwd qw(abs_path);
|
||||||
|
use File::Basename qw(dirname);
|
||||||
|
|
||||||
|
require Git;
|
||||||
|
|
||||||
|
my $DIR = abs_path(dirname($0));
|
||||||
|
|
||||||
|
|
||||||
|
sub usage
|
||||||
|
{
|
||||||
|
print << 'USAGE';
|
||||||
|
usage: git difftool [-t|--tool=<tool>] [-x|--extcmd=<cmd>]
|
||||||
|
[-y|--no-prompt] [-g|--gui]
|
||||||
|
['git diff' options]
|
||||||
|
USAGE
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub setup_environment
|
||||||
|
{
|
||||||
|
$ENV{PATH} = "$DIR:$ENV{PATH}";
|
||||||
|
$ENV{GIT_PAGER} = '';
|
||||||
|
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub exe
|
||||||
|
{
|
||||||
|
my $exe = shift;
|
||||||
|
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
||||||
|
return "$exe.exe";
|
||||||
|
}
|
||||||
|
return $exe;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub generate_command
|
||||||
|
{
|
||||||
|
my @command = (exe('git'), 'diff');
|
||||||
|
my $skip_next = 0;
|
||||||
|
my $idx = -1;
|
||||||
|
my $prompt = '';
|
||||||
|
for my $arg (@ARGV) {
|
||||||
|
$idx++;
|
||||||
|
if ($skip_next) {
|
||||||
|
$skip_next = 0;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '-t' || $arg eq '--tool') {
|
||||||
|
usage() if $#ARGV <= $idx;
|
||||||
|
$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
|
||||||
|
$skip_next = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg =~ /^--tool=/) {
|
||||||
|
$ENV{GIT_DIFF_TOOL} = substr($arg, 7);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '-x' || $arg eq '--extcmd') {
|
||||||
|
usage() if $#ARGV <= $idx;
|
||||||
|
$ENV{GIT_DIFFTOOL_EXTCMD} = $ARGV[$idx + 1];
|
||||||
|
$skip_next = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg =~ /^--extcmd=/) {
|
||||||
|
$ENV{GIT_DIFFTOOL_EXTCMD} = substr($arg, 9);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '-g' || $arg eq '--gui') {
|
||||||
|
eval {
|
||||||
|
my $tool = Git::command_oneline('config',
|
||||||
|
'diff.guitool');
|
||||||
|
if (length($tool)) {
|
||||||
|
$ENV{GIT_DIFF_TOOL} = $tool;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '-y' || $arg eq '--no-prompt') {
|
||||||
|
$prompt = 'no';
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '--prompt') {
|
||||||
|
$prompt = 'yes';
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($arg eq '-h' || $arg eq '--help') {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
push @command, $arg;
|
||||||
|
}
|
||||||
|
if ($prompt eq 'yes') {
|
||||||
|
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
|
||||||
|
} elsif ($prompt eq 'no') {
|
||||||
|
$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
|
||||||
|
}
|
||||||
|
return @command
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_environment();
|
||||||
|
|
||||||
|
# ActiveState Perl for Win32 does not implement POSIX semantics of
|
||||||
|
# exec* system call. It just spawns the given executable and finishes
|
||||||
|
# the starting program, exiting with code 0.
|
||||||
|
# system will at least catch the errors returned by git diff,
|
||||||
|
# allowing the caller of git difftool better handling of failures.
|
||||||
|
my $rc = system(generate_command());
|
||||||
|
exit($rc | ($rc >> 8));
|
72
SparkleShare/Mac/git/libexec/git-core/git-difftool--helper
Executable file
72
SparkleShare/Mac/git/libexec/git-core/git-difftool--helper
Executable file
|
@ -0,0 +1,72 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
||||||
|
# This script is typically launched by using the 'git difftool'
|
||||||
|
# convenience command.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009, 2010 David Aguilar
|
||||||
|
|
||||||
|
TOOL_MODE=diff
|
||||||
|
. git-mergetool--lib
|
||||||
|
|
||||||
|
# difftool.prompt controls the default prompt/no-prompt behavior
|
||||||
|
# and is overridden with $GIT_DIFFTOOL*_PROMPT.
|
||||||
|
should_prompt () {
|
||||||
|
prompt_merge=$(git config --bool mergetool.prompt || echo true)
|
||||||
|
prompt=$(git config --bool difftool.prompt || echo $prompt_merge)
|
||||||
|
if test "$prompt" = true; then
|
||||||
|
test -z "$GIT_DIFFTOOL_NO_PROMPT"
|
||||||
|
else
|
||||||
|
test -n "$GIT_DIFFTOOL_PROMPT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Indicates that --extcmd=... was specified
|
||||||
|
use_ext_cmd () {
|
||||||
|
test -n "$GIT_DIFFTOOL_EXTCMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_merge_tool () {
|
||||||
|
# Merged is the filename as it appears in the work tree
|
||||||
|
# Local is the contents of a/filename
|
||||||
|
# Remote is the contents of b/filename
|
||||||
|
# Custom merge tool commands might use $BASE so we provide it
|
||||||
|
MERGED="$1"
|
||||||
|
LOCAL="$2"
|
||||||
|
REMOTE="$3"
|
||||||
|
BASE="$1"
|
||||||
|
|
||||||
|
# $LOCAL and $REMOTE are temporary files so prompt
|
||||||
|
# the user with the real $MERGED name before launching $merge_tool.
|
||||||
|
if should_prompt; then
|
||||||
|
printf "\nViewing: '$MERGED'\n"
|
||||||
|
if use_ext_cmd; then
|
||||||
|
printf "Hit return to launch '%s': " \
|
||||||
|
"$GIT_DIFFTOOL_EXTCMD"
|
||||||
|
else
|
||||||
|
printf "Hit return to launch '%s': " "$merge_tool"
|
||||||
|
fi
|
||||||
|
read ans
|
||||||
|
fi
|
||||||
|
|
||||||
|
if use_ext_cmd; then
|
||||||
|
export BASE
|
||||||
|
eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
|
||||||
|
else
|
||||||
|
run_merge_tool "$merge_tool"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! use_ext_cmd; then
|
||||||
|
if test -n "$GIT_DIFF_TOOL"; then
|
||||||
|
merge_tool="$GIT_DIFF_TOOL"
|
||||||
|
else
|
||||||
|
merge_tool="$(get_merge_tool)" || exit
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Launch the merge tool on each path provided by 'git diff'
|
||||||
|
while test $# -gt 6
|
||||||
|
do
|
||||||
|
launch_merge_tool "$1" "$2" "$5"
|
||||||
|
shift 7
|
||||||
|
done
|
1
SparkleShare/Mac/git/libexec/git-core/git-fast-export
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fast-export
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
BIN
SparkleShare/Mac/git/libexec/git-core/git-fast-import
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-fast-import
Executable file
Binary file not shown.
1
SparkleShare/Mac/git/libexec/git-core/git-fetch
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fetch
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-fetch-pack
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fetch-pack
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
516
SparkleShare/Mac/git/libexec/git-core/git-filter-branch
Executable file
516
SparkleShare/Mac/git/libexec/git-core/git-filter-branch
Executable file
|
@ -0,0 +1,516 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Rewrite revision history
|
||||||
|
# Copyright (c) Petr Baudis, 2006
|
||||||
|
# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
|
||||||
|
#
|
||||||
|
# Lets you rewrite the revision history of the current branch, creating
|
||||||
|
# a new branch. You can specify a number of filters to modify the commits,
|
||||||
|
# files and trees.
|
||||||
|
|
||||||
|
# The following functions will also be available in the commit filter:
|
||||||
|
|
||||||
|
functions=$(cat << \EOF
|
||||||
|
warn () {
|
||||||
|
echo "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
map()
|
||||||
|
{
|
||||||
|
# if it was not rewritten, take the original
|
||||||
|
if test -r "$workdir/../map/$1"
|
||||||
|
then
|
||||||
|
cat "$workdir/../map/$1"
|
||||||
|
else
|
||||||
|
echo "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# if you run 'skip_commit "$@"' in a commit filter, it will print
|
||||||
|
# the (mapped) parents, effectively skipping the commit.
|
||||||
|
|
||||||
|
skip_commit()
|
||||||
|
{
|
||||||
|
shift;
|
||||||
|
while [ -n "$1" ];
|
||||||
|
do
|
||||||
|
shift;
|
||||||
|
map "$1";
|
||||||
|
shift;
|
||||||
|
done;
|
||||||
|
}
|
||||||
|
|
||||||
|
# if you run 'git_commit_non_empty_tree "$@"' in a commit filter,
|
||||||
|
# it will skip commits that leave the tree untouched, commit the other.
|
||||||
|
git_commit_non_empty_tree()
|
||||||
|
{
|
||||||
|
if test $# = 3 && test "$1" = $(git rev-parse "$3^{tree}"); then
|
||||||
|
map "$3"
|
||||||
|
else
|
||||||
|
git commit-tree "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
# override die(): this version puts in an extra line break, so that
|
||||||
|
# the progress is still visible
|
||||||
|
|
||||||
|
die()
|
||||||
|
{
|
||||||
|
echo >&2
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
eval "$functions"
|
||||||
|
|
||||||
|
# When piped a commit, output a script to set the ident of either
|
||||||
|
# "author" or "committer
|
||||||
|
|
||||||
|
set_ident () {
|
||||||
|
lid="$(echo "$1" | tr "[A-Z]" "[a-z]")"
|
||||||
|
uid="$(echo "$1" | tr "[a-z]" "[A-Z]")"
|
||||||
|
pick_id_script='
|
||||||
|
/^'$lid' /{
|
||||||
|
s/'\''/'\''\\'\'\''/g
|
||||||
|
h
|
||||||
|
s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
|
||||||
|
s/'\''/'\''\'\'\''/g
|
||||||
|
s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p
|
||||||
|
|
||||||
|
g
|
||||||
|
s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
|
||||||
|
s/'\''/'\''\'\'\''/g
|
||||||
|
s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p
|
||||||
|
|
||||||
|
g
|
||||||
|
s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/
|
||||||
|
s/'\''/'\''\'\'\''/g
|
||||||
|
s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p
|
||||||
|
|
||||||
|
q
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
LANG=C LC_ALL=C sed -ne "$pick_id_script"
|
||||||
|
# Ensure non-empty id name.
|
||||||
|
echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac"
|
||||||
|
}
|
||||||
|
|
||||||
|
USAGE="[--env-filter <command>] [--tree-filter <command>]
|
||||||
|
[--index-filter <command>] [--parent-filter <command>]
|
||||||
|
[--msg-filter <command>] [--commit-filter <command>]
|
||||||
|
[--tag-name-filter <command>] [--subdirectory-filter <directory>]
|
||||||
|
[--original <namespace>] [-d <directory>] [-f | --force]
|
||||||
|
[<rev-list options>...]"
|
||||||
|
|
||||||
|
OPTIONS_SPEC=
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
|
if [ "$(is_bare_repository)" = false ]; then
|
||||||
|
git diff-files --ignore-submodules --quiet &&
|
||||||
|
git diff-index --cached --quiet HEAD -- ||
|
||||||
|
die "Cannot rewrite branch(es) with a dirty working directory."
|
||||||
|
fi
|
||||||
|
|
||||||
|
tempdir=.git-rewrite
|
||||||
|
filter_env=
|
||||||
|
filter_tree=
|
||||||
|
filter_index=
|
||||||
|
filter_parent=
|
||||||
|
filter_msg=cat
|
||||||
|
filter_commit=
|
||||||
|
filter_tag_name=
|
||||||
|
filter_subdir=
|
||||||
|
orig_namespace=refs/original/
|
||||||
|
force=
|
||||||
|
prune_empty=
|
||||||
|
remap_to_ancestor=
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
--force|-f)
|
||||||
|
shift
|
||||||
|
force=t
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
--remap-to-ancestor)
|
||||||
|
# deprecated ($remap_to_ancestor is set now automatically)
|
||||||
|
shift
|
||||||
|
remap_to_ancestor=t
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
--prune-empty)
|
||||||
|
shift
|
||||||
|
prune_empty=t
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# all switches take one argument
|
||||||
|
ARG="$1"
|
||||||
|
case "$#" in 1) usage ;; esac
|
||||||
|
shift
|
||||||
|
OPTARG="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
case "$ARG" in
|
||||||
|
-d)
|
||||||
|
tempdir="$OPTARG"
|
||||||
|
;;
|
||||||
|
--env-filter)
|
||||||
|
filter_env="$OPTARG"
|
||||||
|
;;
|
||||||
|
--tree-filter)
|
||||||
|
filter_tree="$OPTARG"
|
||||||
|
;;
|
||||||
|
--index-filter)
|
||||||
|
filter_index="$OPTARG"
|
||||||
|
;;
|
||||||
|
--parent-filter)
|
||||||
|
filter_parent="$OPTARG"
|
||||||
|
;;
|
||||||
|
--msg-filter)
|
||||||
|
filter_msg="$OPTARG"
|
||||||
|
;;
|
||||||
|
--commit-filter)
|
||||||
|
filter_commit="$functions; $OPTARG"
|
||||||
|
;;
|
||||||
|
--tag-name-filter)
|
||||||
|
filter_tag_name="$OPTARG"
|
||||||
|
;;
|
||||||
|
--subdirectory-filter)
|
||||||
|
filter_subdir="$OPTARG"
|
||||||
|
remap_to_ancestor=t
|
||||||
|
;;
|
||||||
|
--original)
|
||||||
|
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$prune_empty,$filter_commit" in
|
||||||
|
,)
|
||||||
|
filter_commit='git commit-tree "$@"';;
|
||||||
|
t,)
|
||||||
|
filter_commit="$functions;"' git_commit_non_empty_tree "$@"';;
|
||||||
|
,*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Cannot set --prune-empty and --commit-filter at the same time"
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$force" in
|
||||||
|
t)
|
||||||
|
rm -rf "$tempdir"
|
||||||
|
;;
|
||||||
|
'')
|
||||||
|
test -d "$tempdir" &&
|
||||||
|
die "$tempdir already exists, please remove it"
|
||||||
|
esac
|
||||||
|
mkdir -p "$tempdir/t" &&
|
||||||
|
tempdir="$(cd "$tempdir"; pwd)" &&
|
||||||
|
cd "$tempdir/t" &&
|
||||||
|
workdir="$(pwd)" ||
|
||||||
|
die ""
|
||||||
|
|
||||||
|
# Remove tempdir on exit
|
||||||
|
trap 'cd ../..; rm -rf "$tempdir"' 0
|
||||||
|
|
||||||
|
ORIG_GIT_DIR="$GIT_DIR"
|
||||||
|
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
|
||||||
|
ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE"
|
||||||
|
GIT_WORK_TREE=.
|
||||||
|
export GIT_DIR GIT_WORK_TREE
|
||||||
|
|
||||||
|
# Make sure refs/original is empty
|
||||||
|
git for-each-ref > "$tempdir"/backup-refs || exit
|
||||||
|
while read sha1 type name
|
||||||
|
do
|
||||||
|
case "$force,$name" in
|
||||||
|
,$orig_namespace*)
|
||||||
|
die "Cannot create a new backup.
|
||||||
|
A previous backup already exists in $orig_namespace
|
||||||
|
Force overwriting the backup with -f"
|
||||||
|
;;
|
||||||
|
t,$orig_namespace*)
|
||||||
|
git update-ref -d "$name" $sha1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < "$tempdir"/backup-refs
|
||||||
|
|
||||||
|
# The refs should be updated if their heads were rewritten
|
||||||
|
git rev-parse --no-flags --revs-only --symbolic-full-name \
|
||||||
|
--default HEAD "$@" > "$tempdir"/raw-heads || exit
|
||||||
|
sed -e '/^^/d' "$tempdir"/raw-heads >"$tempdir"/heads
|
||||||
|
|
||||||
|
test -s "$tempdir"/heads ||
|
||||||
|
die "Which ref do you want to rewrite?"
|
||||||
|
|
||||||
|
GIT_INDEX_FILE="$(pwd)/../index"
|
||||||
|
export GIT_INDEX_FILE
|
||||||
|
|
||||||
|
# map old->new commit ids for rewriting parents
|
||||||
|
mkdir ../map || die "Could not create map/ directory"
|
||||||
|
|
||||||
|
# we need "--" only if there are no path arguments in $@
|
||||||
|
nonrevs=$(git rev-parse --no-revs "$@") || exit
|
||||||
|
if test -z "$nonrevs"
|
||||||
|
then
|
||||||
|
dashdash=--
|
||||||
|
else
|
||||||
|
dashdash=
|
||||||
|
remap_to_ancestor=t
|
||||||
|
fi
|
||||||
|
|
||||||
|
rev_args=$(git rev-parse --revs-only "$@")
|
||||||
|
|
||||||
|
case "$filter_subdir" in
|
||||||
|
"")
|
||||||
|
eval set -- "$(git rev-parse --sq --no-revs "$@")"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \
|
||||||
|
"$filter_subdir")"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
git rev-list --reverse --topo-order --default HEAD \
|
||||||
|
--parents --simplify-merges $rev_args "$@" > ../revs ||
|
||||||
|
die "Could not get the commits"
|
||||||
|
commits=$(wc -l <../revs | tr -d " ")
|
||||||
|
|
||||||
|
test $commits -eq 0 && die "Found nothing to rewrite"
|
||||||
|
|
||||||
|
# Rewrite the commits
|
||||||
|
|
||||||
|
git_filter_branch__commit_count=0
|
||||||
|
while read commit parents; do
|
||||||
|
git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
|
||||||
|
printf "\rRewrite $commit ($git_filter_branch__commit_count/$commits)"
|
||||||
|
|
||||||
|
case "$filter_subdir" in
|
||||||
|
"")
|
||||||
|
git read-tree -i -m $commit
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# The commit may not have the subdirectory at all
|
||||||
|
err=$(git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
|
||||||
|
if ! git rev-parse -q --verify $commit:"$filter_subdir"
|
||||||
|
then
|
||||||
|
rm -f "$GIT_INDEX_FILE"
|
||||||
|
else
|
||||||
|
echo >&2 "$err"
|
||||||
|
false
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
esac || die "Could not initialize the index"
|
||||||
|
|
||||||
|
GIT_COMMIT=$commit
|
||||||
|
export GIT_COMMIT
|
||||||
|
git cat-file commit "$commit" >../commit ||
|
||||||
|
die "Cannot read commit $commit"
|
||||||
|
|
||||||
|
eval "$(set_ident AUTHOR <../commit)" ||
|
||||||
|
die "setting author failed for commit $commit"
|
||||||
|
eval "$(set_ident COMMITTER <../commit)" ||
|
||||||
|
die "setting committer failed for commit $commit"
|
||||||
|
eval "$filter_env" < /dev/null ||
|
||||||
|
die "env filter failed: $filter_env"
|
||||||
|
|
||||||
|
if [ "$filter_tree" ]; then
|
||||||
|
git checkout-index -f -u -a ||
|
||||||
|
die "Could not checkout the index"
|
||||||
|
# files that $commit removed are now still in the working tree;
|
||||||
|
# remove them, else they would be added again
|
||||||
|
git clean -d -q -f -x
|
||||||
|
eval "$filter_tree" < /dev/null ||
|
||||||
|
die "tree filter failed: $filter_tree"
|
||||||
|
|
||||||
|
(
|
||||||
|
git diff-index -r --name-only --ignore-submodules $commit &&
|
||||||
|
git ls-files --others
|
||||||
|
) > "$tempdir"/tree-state || exit
|
||||||
|
git update-index --add --replace --remove --stdin \
|
||||||
|
< "$tempdir"/tree-state || exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval "$filter_index" < /dev/null ||
|
||||||
|
die "index filter failed: $filter_index"
|
||||||
|
|
||||||
|
parentstr=
|
||||||
|
for parent in $parents; do
|
||||||
|
for reparent in $(map "$parent"); do
|
||||||
|
parentstr="$parentstr -p $reparent"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
if [ "$filter_parent" ]; then
|
||||||
|
parentstr="$(echo "$parentstr" | eval "$filter_parent")" ||
|
||||||
|
die "parent filter failed: $filter_parent"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -e '1,/^$/d' <../commit | \
|
||||||
|
eval "$filter_msg" > ../message ||
|
||||||
|
die "msg filter failed: $filter_msg"
|
||||||
|
/bin/sh -c "$filter_commit" "git commit-tree" \
|
||||||
|
$(git write-tree) $parentstr < ../message > ../map/$commit ||
|
||||||
|
die "could not write rewritten commit"
|
||||||
|
done <../revs
|
||||||
|
|
||||||
|
# If we are filtering for paths, as in the case of a subdirectory
|
||||||
|
# filter, it is possible that a specified head is not in the set of
|
||||||
|
# rewritten commits, because it was pruned by the revision walker.
|
||||||
|
# Ancestor remapping fixes this by mapping these heads to the unique
|
||||||
|
# nearest ancestor that survived the pruning.
|
||||||
|
|
||||||
|
if test "$remap_to_ancestor" = t
|
||||||
|
then
|
||||||
|
while read ref
|
||||||
|
do
|
||||||
|
sha1=$(git rev-parse "$ref"^0)
|
||||||
|
test -f "$workdir"/../map/$sha1 && continue
|
||||||
|
ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
|
||||||
|
test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
|
||||||
|
done < "$tempdir"/heads
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Finally update the refs
|
||||||
|
|
||||||
|
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
||||||
|
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
||||||
|
echo
|
||||||
|
while read ref
|
||||||
|
do
|
||||||
|
# avoid rewriting a ref twice
|
||||||
|
test -f "$orig_namespace$ref" && continue
|
||||||
|
|
||||||
|
sha1=$(git rev-parse "$ref"^0)
|
||||||
|
rewritten=$(map $sha1)
|
||||||
|
|
||||||
|
test $sha1 = "$rewritten" &&
|
||||||
|
warn "WARNING: Ref '$ref' is unchanged" &&
|
||||||
|
continue
|
||||||
|
|
||||||
|
case "$rewritten" in
|
||||||
|
'')
|
||||||
|
echo "Ref '$ref' was deleted"
|
||||||
|
git update-ref -m "filter-branch: delete" -d "$ref" $sha1 ||
|
||||||
|
die "Could not delete $ref"
|
||||||
|
;;
|
||||||
|
$_x40)
|
||||||
|
echo "Ref '$ref' was rewritten"
|
||||||
|
if ! git update-ref -m "filter-branch: rewrite" \
|
||||||
|
"$ref" $rewritten $sha1 2>/dev/null; then
|
||||||
|
if test $(git cat-file -t "$ref") = tag; then
|
||||||
|
if test -z "$filter_tag_name"; then
|
||||||
|
warn "WARNING: You said to rewrite tagged commits, but not the corresponding tag."
|
||||||
|
warn "WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
die "Could not rewrite $ref"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# NEEDSWORK: possibly add -Werror, making this an error
|
||||||
|
warn "WARNING: '$ref' was rewritten into multiple commits:"
|
||||||
|
warn "$rewritten"
|
||||||
|
warn "WARNING: Ref '$ref' points to the first one now."
|
||||||
|
rewritten=$(echo "$rewritten" | head -n 1)
|
||||||
|
git update-ref -m "filter-branch: rewrite to first" \
|
||||||
|
"$ref" $rewritten $sha1 ||
|
||||||
|
die "Could not rewrite $ref"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 ||
|
||||||
|
exit
|
||||||
|
done < "$tempdir"/heads
|
||||||
|
|
||||||
|
# TODO: This should possibly go, with the semantics that all positive given
|
||||||
|
# refs are updated, and their original heads stored in refs/original/
|
||||||
|
# Filter tags
|
||||||
|
|
||||||
|
if [ "$filter_tag_name" ]; then
|
||||||
|
git for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
|
||||||
|
while read sha1 type ref; do
|
||||||
|
ref="${ref#refs/tags/}"
|
||||||
|
# XXX: Rewrite tagged trees as well?
|
||||||
|
if [ "$type" != "commit" -a "$type" != "tag" ]; then
|
||||||
|
continue;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$type" = "tag" ]; then
|
||||||
|
# Dereference to a commit
|
||||||
|
sha1t="$sha1"
|
||||||
|
sha1="$(git rev-parse -q "$sha1"^{commit})" || continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -f "../map/$sha1" ] || continue
|
||||||
|
new_sha1="$(cat "../map/$sha1")"
|
||||||
|
GIT_COMMIT="$sha1"
|
||||||
|
export GIT_COMMIT
|
||||||
|
new_ref="$(echo "$ref" | eval "$filter_tag_name")" ||
|
||||||
|
die "tag name filter failed: $filter_tag_name"
|
||||||
|
|
||||||
|
echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
|
||||||
|
|
||||||
|
if [ "$type" = "tag" ]; then
|
||||||
|
new_sha1=$( ( printf 'object %s\ntype commit\ntag %s\n' \
|
||||||
|
"$new_sha1" "$new_ref"
|
||||||
|
git cat-file tag "$ref" |
|
||||||
|
sed -n \
|
||||||
|
-e '1,/^$/{
|
||||||
|
/^object /d
|
||||||
|
/^type /d
|
||||||
|
/^tag /d
|
||||||
|
}' \
|
||||||
|
-e '/^-----BEGIN PGP SIGNATURE-----/q' \
|
||||||
|
-e 'p' ) |
|
||||||
|
git mktag) ||
|
||||||
|
die "Could not create new tag object for $ref"
|
||||||
|
if git cat-file tag "$ref" | \
|
||||||
|
sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
warn "gpg signature stripped from tag object $sha1t"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
git update-ref "refs/tags/$new_ref" "$new_sha1" ||
|
||||||
|
die "Could not write tag $new_ref"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
rm -rf "$tempdir"
|
||||||
|
|
||||||
|
trap - 0
|
||||||
|
|
||||||
|
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
|
||||||
|
test -z "$ORIG_GIT_DIR" || {
|
||||||
|
GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
|
||||||
|
}
|
||||||
|
test -z "$ORIG_GIT_WORK_TREE" || {
|
||||||
|
GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
|
||||||
|
export GIT_WORK_TREE
|
||||||
|
}
|
||||||
|
test -z "$ORIG_GIT_INDEX_FILE" || {
|
||||||
|
GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
|
||||||
|
export GIT_INDEX_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(is_bare_repository)" = false ]; then
|
||||||
|
git read-tree -u -m HEAD || exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
1
SparkleShare/Mac/git/libexec/git-core/git-fmt-merge-msg
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fmt-merge-msg
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-for-each-ref
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-for-each-ref
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-format-patch
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-format-patch
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-fsck
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fsck
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-fsck-objects
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-fsck-objects
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-gc
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-gc
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-get-tar-commit-id
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-get-tar-commit-id
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-grep
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-grep
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
8
SparkleShare/Mac/git/libexec/git-core/git-gui
Executable file
8
SparkleShare/Mac/git/libexec/git-core/git-gui
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
if test "z$*" = zversion ||
|
||||||
|
test "z$*" = z--version
|
||||||
|
then
|
||||||
|
echo 'git-gui version 0.13.0.8.g8f85'
|
||||||
|
else
|
||||||
|
exec '/usr/local/git/share/git-gui/lib/Git Gui.app/Contents/MacOS/Wish' "$0" "$@"
|
||||||
|
fi
|
66
SparkleShare/Mac/git/libexec/git-core/git-gui--askpass
Executable file
66
SparkleShare/Mac/git/libexec/git-core/git-gui--askpass
Executable file
|
@ -0,0 +1,66 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Tcl ignores the next line -*- tcl -*- \
|
||||||
|
exec wish "$0" -- "$@"
|
||||||
|
|
||||||
|
# This is a trivial implementation of an SSH_ASKPASS handler.
|
||||||
|
# Git-gui uses this script if none are already configured.
|
||||||
|
|
||||||
|
package require Tk
|
||||||
|
|
||||||
|
set answer {}
|
||||||
|
set yesno 0
|
||||||
|
set rc 255
|
||||||
|
|
||||||
|
if {$argc < 1} {
|
||||||
|
set prompt "Enter your OpenSSH passphrase:"
|
||||||
|
} else {
|
||||||
|
set prompt [join $argv " "]
|
||||||
|
if {[regexp -nocase {\(yes\/no\)\?\s*$} $prompt]} {
|
||||||
|
set yesno 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message .m -text $prompt -justify center -aspect 4000
|
||||||
|
pack .m -side top -fill x -padx 20 -pady 20 -expand 1
|
||||||
|
|
||||||
|
entry .e -textvariable answer -width 50
|
||||||
|
pack .e -side top -fill x -padx 10 -pady 10
|
||||||
|
|
||||||
|
if {!$yesno} {
|
||||||
|
.e configure -show "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
frame .b
|
||||||
|
button .b.ok -text OK -command finish
|
||||||
|
button .b.cancel -text Cancel -command cancel
|
||||||
|
|
||||||
|
pack .b.ok -side left -expand 1
|
||||||
|
pack .b.cancel -side right -expand 1
|
||||||
|
pack .b -side bottom -fill x -padx 10 -pady 10
|
||||||
|
|
||||||
|
bind . <Visibility> {focus -force .e}
|
||||||
|
bind . <Key-Return> [list .b.ok invoke]
|
||||||
|
bind . <Key-Escape> [list .b.cancel invoke]
|
||||||
|
bind . <Destroy> {set rc $rc}
|
||||||
|
|
||||||
|
proc cancel {} {
|
||||||
|
set ::rc 255
|
||||||
|
}
|
||||||
|
|
||||||
|
proc finish {} {
|
||||||
|
if {$::yesno} {
|
||||||
|
if {$::answer ne "yes" && $::answer ne "no"} {
|
||||||
|
tk_messageBox -icon error -title "Error" -type ok \
|
||||||
|
-message "Only 'yes' or 'no' input allowed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
puts $::answer
|
||||||
|
set ::rc 0
|
||||||
|
}
|
||||||
|
|
||||||
|
wm title . "OpenSSH"
|
||||||
|
tk::PlaceWindow .
|
||||||
|
vwait rc
|
||||||
|
exit $rc
|
1
SparkleShare/Mac/git/libexec/git-core/git-hash-object
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-hash-object
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
1
SparkleShare/Mac/git/libexec/git-core/git-help
Symbolic link
1
SparkleShare/Mac/git/libexec/git-core/git-help
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../bin/git
|
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-backend
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-backend
Executable file
Binary file not shown.
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-fetch
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-fetch
Executable file
Binary file not shown.
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-push
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-http-push
Executable file
Binary file not shown.
BIN
SparkleShare/Mac/git/libexec/git-core/git-imap-send
Executable file
BIN
SparkleShare/Mac/git/libexec/git-core/git-imap-send
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue