mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
svn 1.7 as additional plugin
This commit is contained in:
@@ -52,6 +52,15 @@
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<category name="#org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator">
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</category>
|
||||
<category name="#org.jetbrains.idea.svn.history.FirstInBranch">
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</category>
|
||||
|
||||
<root>
|
||||
<priority value="INFO"/>
|
||||
<appender-ref ref="DIALOG"/>
|
||||
|
||||
@@ -240,6 +240,9 @@ public def layoutCommunityPlugins(String home) {
|
||||
}
|
||||
}
|
||||
|
||||
layoutPlugin("svn4ideaOld") {
|
||||
fileset(dir: "$home/plugins/svn4ideaOld/lib", excludes: "**/svnkitsrc.zip")
|
||||
}
|
||||
layoutPlugin("svn4idea") {
|
||||
fileset(dir: "$home/plugins/svn4idea/lib", excludes: "**/svnkitsrc.zip")
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
This Idea plugin integrates Idea with Subversion.
|
||||
|
||||
The plugin tries to be as tightly integrated with Idea as possible.
|
||||
|
||||
Like the CVS integration it uses Idea's project view to display the workspace.
|
||||
Changed files are color coded in the project view and the editor just as in the CVS integration.
|
||||
|
||||
All files & directories in the project directory, that are in the subversion repository are tracked during
|
||||
move and rename operations.
|
||||
|
||||
Files & directories created through Idea in the projects source path are automatically tracked.
|
||||
You can configure whether the new files shall be added to the
|
||||
subversion repository (Always, Ask, Never).
|
||||
|
||||
Additional directories to be tracked for newly created files can be entered in
|
||||
the "Additional Path" list on the configuration page.
|
||||
|
||||
Files & directories in a subversion repository which are deleted through Idea are automatically tracked.
|
||||
You can configure whether the deleted files shall also be deleted from the subversion repository (Always, Ask, Never).
|
||||
|
||||
Subversion operations can be trieggered from the Subversion menu (tools/Subversion) or from the context menu.
|
||||
|
||||
For exended subversion operations (administration, blaming, properties etc) you can start the SvnUp
|
||||
dialog from the Subversion menu (tools/Subversion/SvnUp).
|
||||
@@ -0,0 +1,26 @@
|
||||
[The "BSD licence"]
|
||||
Copyright (c) 2003-2008 Terence Parr
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,55 @@
|
||||
This license applies to all portions of Subversion which are not
|
||||
externally-maintained libraries (e.g. apr/, apr-util/, and neon/).
|
||||
Such libraries have their own licenses; we recommend you read them, as
|
||||
their terms may differ from the terms below.
|
||||
|
||||
This is version 1 of this license. It is also available online at
|
||||
http://subversion.tigris.org/license-1.html. If newer versions of
|
||||
this license are posted there (the same URL, but with the version
|
||||
number incremented: .../license-2.html, .../license-3.html, and so
|
||||
on), you may use a newer version instead, at your option.
|
||||
|
||||
====================================================================
|
||||
Copyright (c) 2000-2005 CollabNet. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The end-user documentation included with the redistribution, if
|
||||
any, must include the following acknowledgment: "This product includes
|
||||
software developed by CollabNet (http://www.Collab.Net/)."
|
||||
Alternately, this acknowledgment may appear in the software itself, if
|
||||
and wherever such third-party acknowledgments normally appear.
|
||||
|
||||
4. The hosted project names must not be used to endorse or promote
|
||||
products derived from this software without prior written
|
||||
permission. For written permission, please contact info@collab.net.
|
||||
|
||||
5. Products derived from this software may not use the "Tigris" name
|
||||
nor may "Tigris" appear in their names without prior written
|
||||
permission of CollabNet.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
====================================================================
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of CollabNet.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Copyright (c) 2008 Timothy Wall, All Rights Reserved
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
@@ -0,0 +1,48 @@
|
||||
Sequence Library License
|
||||
|
||||
This license applies to all portions of the Sequence library, which
|
||||
are not externally-maintained libraries (e.g. junit or jsch).
|
||||
====================================================================
|
||||
Copyright (c) 2000-2008 SyntEvo GmbH, Ainring, GERMANY.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The end-user documentation included with the redistribution, if
|
||||
any, must include the following acknowledgment: "This product includes
|
||||
software developed by SyntEvo GmbH, Ainring, GERMANY."
|
||||
Alternately, this acknowledgment may appear in the software itself, if
|
||||
and wherever such third-party acknowledgments normally appear.
|
||||
|
||||
4. The hosted project names must not be used to endorse or promote
|
||||
products derived from this software without prior written
|
||||
permission. For written permission, please contact
|
||||
info@syntevo.com.
|
||||
|
||||
5. Neither the name of SyntEvo GmbH nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL SyntEvo GmbH OR HIS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
====================================================================
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2009-2010 TMate Software Ltd
|
||||
|
||||
As part of SVNKit library, SQLJet library is distributed under
|
||||
the terms of TMate Open Source License (see http://svnkit.com/license.html).
|
||||
Otherwise, outside of SVNKit library, the following licensing terms
|
||||
are applicable for SQLJet library:
|
||||
|
||||
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; version 2 of the License.
|
||||
|
||||
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.
|
||||
|
||||
For information on how to redistribute this software under
|
||||
the terms of a license other than GNU General Public License
|
||||
contact TMate Software at support@sqljet.com
|
||||
@@ -0,0 +1,88 @@
|
||||
Copyright (c) 2007-2008 Trilead AG (http://www.trilead.com)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
a.) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
b.) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
c.) Neither the name of Trilead nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Trilead SSH-2 for Java includes code that was written by Dr. Christian Plattner
|
||||
during his PhD at ETH Zurich. The license states the following:
|
||||
|
||||
Copyright (c) 2005 - 2006 Swiss Federal Institute of Technology (ETH Zurich),
|
||||
Department of Computer Science (http://www.inf.ethz.ch),
|
||||
Christian Plattner. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
a.) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
b.) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
c.) Neither the name of ETH Zurich nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The Java implementations of the AES, Blowfish and 3DES ciphers have been
|
||||
taken (and slightly modified) from the cryptography package released by
|
||||
"The Legion Of The Bouncy Castle".
|
||||
|
||||
Their license states the following:
|
||||
|
||||
Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
|
||||
(http://www.bouncycastle.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,139 +1,139 @@
|
||||
<idea-plugin version="2">
|
||||
<name>Subversion Integration</name>
|
||||
<id>Subversion</id>
|
||||
<name>Subversion 1.7 Experimental Integration</name>
|
||||
<id>Subversion 1.7</id>
|
||||
<version>1.0</version>
|
||||
<category>VCS Integration</category>
|
||||
|
||||
<depends>com.intellij.modules.vcs</depends>
|
||||
|
||||
<vendor logo="/general/ijLogo.png">JetBrains</vendor>
|
||||
<resource-bundle>org.jetbrains.idea.svn.SvnBundle</resource-bundle>
|
||||
<resource-bundle>org.jetbrains.idea.svn17.SvnBundle</resource-bundle>
|
||||
|
||||
<project-components>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.idea.svn.SvnFileUrlMappingImpl</implementation-class>
|
||||
<implementation-class>org.jetbrains.idea.svn17.SvnFileUrlMappingImpl17</implementation-class>
|
||||
<option name="workspace" value="true"/>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
<action id="Subversion.ImportToSVNRepository" class="org.jetbrains.idea.svn.actions.ImportToRepositoryAction">
|
||||
<action id="Subversion17.ImportToSVNRepository" class="org.jetbrains.idea.svn17.actions.ImportToRepositoryAction">
|
||||
<add-to-group group-id="Vcs.Import"/>
|
||||
</action>
|
||||
<action id="Subversion.BrowseSVNRepository" class="org.jetbrains.idea.svn.actions.BrowseRepositoryAction">
|
||||
<action id="Subversion17.BrowseSVNRepository" class="org.jetbrains.idea.svn17.actions.BrowseRepositoryAction">
|
||||
<add-to-group group-id="Vcs.Browse"/>
|
||||
</action>
|
||||
<action id="Subversion.ShareWholeProject" class="org.jetbrains.idea.svn.actions.ShareWholeProject">
|
||||
<action id="Subversion17.ShareWholeProject" class="org.jetbrains.idea.svn17.actions.ShareWholeProject">
|
||||
<add-to-group group-id="Vcs.Import"/>
|
||||
</action>
|
||||
|
||||
<group id="SubversionFilePopupGroup" popup="true" class="org.jetbrains.idea.svn.actions.SubversionGroup">
|
||||
<group id="SubversionFilePopupGroup17" popup="true" class="org.jetbrains.idea.svn17.actions.SubversionGroup">
|
||||
<add-to-group group-id="VcsGroup" anchor="last"/>
|
||||
<add-to-group group-id="VcsGlobalGroup" anchor="after" relative-to-action="Vcs.Specific"/>
|
||||
</group>
|
||||
|
||||
|
||||
<action id="IntegrateChangeSetAction" class="org.jetbrains.idea.svn.actions.IntegrateChangeSetAction" popup="true" icon="/icons/IntegrateToBranch.png">
|
||||
<action id="IntegrateChangeSetAction17" class="org.jetbrains.idea.svn17.actions.IntegrateChangeSetAction" popup="true" icon="/icons/IntegrateToBranch.png">
|
||||
<add-to-group group-id="RepositoryChangesBrowserToolbar" anchor="last"/>
|
||||
</action>
|
||||
|
||||
<action id="PropertiesDiff" class="org.jetbrains.idea.svn.actions.ShowPropertiesDiffAction" popup="true" icon="/icons/PropertiesDiff.png">
|
||||
<action id="PropertiesDiff17" class="org.jetbrains.idea.svn17.actions.ShowPropertiesDiffAction" popup="true" icon="/icons/PropertiesDiff.png">
|
||||
<add-to-group group-id="RepositoryChangesBrowserToolbar" anchor="last"/>
|
||||
</action>
|
||||
|
||||
<action id="AlienPropertiesLocalDiff" class="org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAlienAction" popup="true">
|
||||
<action id="AlienPropertiesLocalDiff17" class="org.jetbrains.idea.svn17.actions.ShowPropertiesDiffWithLocalAlienAction" popup="true">
|
||||
<add-to-group group-id="AlienCommitChangesDialog.AdditionalActions" anchor="last"/>
|
||||
</action>
|
||||
|
||||
<group id="SubversionGroup">
|
||||
<action id="Subversion.Share" class="org.jetbrains.idea.svn.actions.ShareProjectAction"/>
|
||||
<group id="SubversionGroup17">
|
||||
<action id="Subversion17.Share" class="org.jetbrains.idea.svn17.actions.ShareProjectAction"/>
|
||||
<separator/>
|
||||
<action id="Subversion.Add" class="org.jetbrains.idea.svn.actions.AddAction"/>
|
||||
<action id="Subversion17.Add" class="org.jetbrains.idea.svn17.actions.AddAction"/>
|
||||
<reference id="CheckinFiles"/>
|
||||
<reference id="UpdateFiles"/>
|
||||
<reference id="IntegrateFiles"/>
|
||||
<reference id="CheckStatusForFiles"/>
|
||||
<separator/>
|
||||
<action id="Subversion.ShowProperties" class="org.jetbrains.idea.svn.actions.ShowPropertiesAction"/>
|
||||
<action id="Subversion.SetProperty" class="org.jetbrains.idea.svn.actions.SetPropertyAction"/>
|
||||
<action id="ShowPropertiesDiffVsLocal" class="org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAction" icon="/icons/PropertiesDiffWithLocal.png">
|
||||
<action id="Subversion17.ShowProperties" class="org.jetbrains.idea.svn17.actions.ShowPropertiesAction"/>
|
||||
<action id="Subversion17.SetProperty" class="org.jetbrains.idea.svn17.actions.SetPropertyAction"/>
|
||||
<action id="ShowPropertiesDiffVsLocal17" class="org.jetbrains.idea.svn17.actions.ShowPropertiesDiffWithLocalAction" icon="/icons/PropertiesDiffWithLocal.png">
|
||||
</action>
|
||||
<reference id="ChangesView.Rollback"/>
|
||||
<action id="Subversion.Resolve" class="org.jetbrains.idea.svn.actions.ResolveAction"/>
|
||||
<action id="Subversion.MarkResolved" class="org.jetbrains.idea.svn.actions.MarkResolvedAction"/>
|
||||
<action id="Subversion.MarkTreeResolved" class="org.jetbrains.idea.svn.actions.MarkTreeConflictResolvedAction"/>
|
||||
<action id="Subversion.Clenaup" class="org.jetbrains.idea.svn.actions.CleanupAction"/>
|
||||
<action id="Subversion17.Resolve" class="org.jetbrains.idea.svn17.actions.ResolveAction"/>
|
||||
<action id="Subversion17.MarkResolved" class="org.jetbrains.idea.svn17.actions.MarkResolvedAction"/>
|
||||
<action id="Subversion17.MarkTreeResolved" class="org.jetbrains.idea.svn17.actions.MarkTreeConflictResolvedAction"/>
|
||||
<action id="Subversion17.Clenaup" class="org.jetbrains.idea.svn17.actions.CleanupAction"/>
|
||||
<separator/>
|
||||
<reference id="Show.Current.Revision"/>
|
||||
<reference id="Compare.SameVersion" text="Compare with BASE revision"/>
|
||||
<reference id="Compare.LastVersion" text="Compare with revision at HEAD"/>
|
||||
<reference id="Compare.Selected"/>
|
||||
<action id="Subversion.CompareWithBranch" class="org.jetbrains.idea.svn.actions.CompareWithBranchAction"/>
|
||||
<action id="Subversion17.CompareWithBranch" class="org.jetbrains.idea.svn17.actions.CompareWithBranchAction"/>
|
||||
<reference id="Vcs.ShowTabbedFileHistory"/>
|
||||
<reference id="Vcs.ShowHistoryForBlock"/>
|
||||
<reference id="Annotate"/>
|
||||
<action id="Subversion.Copy" class="org.jetbrains.idea.svn.actions.CopyAction"/>
|
||||
<action id="Subversion17.Copy" class="org.jetbrains.idea.svn17.actions.CopyAction"/>
|
||||
<separator/>
|
||||
<action id="Subversion.Lock" class="org.jetbrains.idea.svn.actions.LockAction"/>
|
||||
<action id="Subversion.Unlock" class="org.jetbrains.idea.svn.actions.UnlockAction"/>
|
||||
<action id="Subversion.Relocate" class="org.jetbrains.idea.svn.actions.RelocateAction"/>
|
||||
<action id="Subversion17.Lock" class="org.jetbrains.idea.svn17.actions.LockAction"/>
|
||||
<action id="Subversion17.Unlock" class="org.jetbrains.idea.svn17.actions.UnlockAction"/>
|
||||
<action id="Subversion17.Relocate" class="org.jetbrains.idea.svn17.actions.RelocateAction"/>
|
||||
<separator/>
|
||||
<reference id="ChangesView.Browse"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="SubversionFilePopupGroup" anchor="last"/>
|
||||
<add-to-group group-id="SubversionFilePopupGroup17" anchor="last"/>
|
||||
</group>
|
||||
<action id="Subversion.MarkLocallyDeletedTreeResolved" class="org.jetbrains.idea.svn.actions.MarkLocallyDeletedTreeConflictResolvedAction">
|
||||
<action id="Subversion17.MarkLocallyDeletedTreeResolved" class="org.jetbrains.idea.svn17.actions.MarkLocallyDeletedTreeConflictResolvedAction">
|
||||
<add-to-group group-id="ChangesViewPopupMenu" anchor="after" relative-to-action="ChangesView.Diff"/>
|
||||
</action>
|
||||
<reference id="Subversion.MarkTreeResolved">
|
||||
<reference id="Subversion17.MarkTreeResolved">
|
||||
<add-to-group group-id="ChangesViewPopupMenu" anchor="after" relative-to-action="ChangesView.Diff"/>
|
||||
</reference>
|
||||
<group id="SubversionUpdateActionGroup" class="org.jetbrains.idea.svn.actions.SubversionGroup">
|
||||
<reference id="Subversion.Add"/>
|
||||
<group id="SubversionUpdateActionGroup17" class="org.jetbrains.idea.svn17.actions.SubversionGroup">
|
||||
<reference id="Subversion17.Add"/>
|
||||
<reference id="ChangesView.Rollback"/>
|
||||
<reference id="Subversion.Resolve"/>
|
||||
<reference id="Subversion.MarkResolved"/>
|
||||
<reference id="Subversion17.Resolve"/>
|
||||
<reference id="Subversion17.MarkResolved"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="UpdateActionGroup" anchor="first"/>
|
||||
</group>
|
||||
|
||||
<group id="IgnoreChoicesGroup" popup="true" class="org.jetbrains.idea.svn.actions.IgnoreActionGroup">
|
||||
<add-to-group group-id="SubversionGroup" relative-to-action="Subversion.Add" anchor="after"/>
|
||||
<group id="IgnoreChoicesGroup17" popup="true" class="org.jetbrains.idea.svn17.actions.IgnoreActionGroup">
|
||||
<add-to-group group-id="SubversionGroup17" relative-to-action="Subversion17.Add" anchor="after"/>
|
||||
</group>
|
||||
|
||||
<action class="org.jetbrains.idea.svn.dialogs.MergeFromAction" id="Subversion.MergeFrom">
|
||||
<action class="org.jetbrains.idea.svn17.dialogs.MergeFromAction" id="Subversion17.MergeFrom">
|
||||
<add-to-group relative-to-action="Vcs.IntegrateProject" anchor="after" group-id="VcsGlobalGroup"/>
|
||||
</action>
|
||||
<action class="org.jetbrains.idea.svn.actions.CleanupProjectAction" id="Subversion.CleanupProject">
|
||||
<add-to-group group-id="VcsGlobalGroup" anchor="after" relative-to-action="Subversion.MergeFrom"/>
|
||||
<action class="org.jetbrains.idea.svn17.actions.CleanupProjectAction" id="Subversion17.CleanupProject">
|
||||
<add-to-group group-id="VcsGlobalGroup" anchor="after" relative-to-action="Subversion17.MergeFrom"/>
|
||||
</action>
|
||||
</actions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
|
||||
<checkoutProvider implementation="org.jetbrains.idea.svn.checkout.SvnCheckoutProvider"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn.SvnApplicationSettings"
|
||||
serviceImplementation="org.jetbrains.idea.svn.SvnApplicationSettings"/>
|
||||
<projectService serviceImplementation="org.jetbrains.idea.svn.SvnConfiguration"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn.SvnBranchConfigurationManager"
|
||||
serviceImplementation="org.jetbrains.idea.svn.SvnBranchConfigurationManager"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn.history.LoadedRevisionsCache"
|
||||
serviceImplementation="org.jetbrains.idea.svn.history.LoadedRevisionsCache"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache"
|
||||
serviceImplementation="org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn.SvnLoadedBrachesStorage"
|
||||
serviceImplementation="org.jetbrains.idea.svn.SvnLoadedBrachesStorage"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn.SvnBranchMapperManager"
|
||||
serviceImplementation="org.jetbrains.idea.svn.SvnBranchMapperManager"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn.dialogs.browserCache.SvnRepositoryCache"
|
||||
serviceImplementation="org.jetbrains.idea.svn.dialogs.browserCache.SvnRepositoryCache"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn.dialogs.browserCache.Loader"
|
||||
serviceImplementation="org.jetbrains.idea.svn.dialogs.browserCache.CacheLoader"/>
|
||||
<checkoutProvider implementation="org.jetbrains.idea.svn17.checkout.SvnCheckoutProvider"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn17.SvnApplicationSettings17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.SvnApplicationSettings17"/>
|
||||
<projectService serviceImplementation="org.jetbrains.idea.svn17.SvnConfiguration17"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn17.SvnBranchConfigurationManager17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.SvnBranchConfigurationManager17"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn17.history.LoadedRevisionsCache17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.history.LoadedRevisionsCache17"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn17.mergeinfo.SvnMergeInfoCache17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.mergeinfo.SvnMergeInfoCache17"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.svn17.SvnLoadedBrachesStorage17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.SvnLoadedBrachesStorage17"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn17.SvnBranchMapperManager17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.SvnBranchMapperManager17"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn17.dialogs.browserCache.SvnRepositoryCache17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.dialogs.browserCache.SvnRepositoryCache17"/>
|
||||
<applicationService serviceInterface="org.jetbrains.idea.svn17.dialogs.browserCache.Loader17"
|
||||
serviceImplementation="org.jetbrains.idea.svn17.dialogs.browserCache.CacheLoader17"/>
|
||||
|
||||
<vcs name="svn" vcsClass="org.jetbrains.idea.svn.SvnVcs" displayName="Subversion" administrativeAreaName=".svn, _svn"/>
|
||||
<vcs name="svn17" vcsClass="org.jetbrains.idea.svn17.SvnVcs17" displayName="Subversion 1.7 Experimental" administrativeAreaName=".svn, _svn"/>
|
||||
|
||||
<ComponentRoamingType component="SvnConfiguration" type="DISABLED"/>
|
||||
<vcsPopupProvider implementation="org.jetbrains.idea.svn.actions.SvnQuickListContentProvider"/>
|
||||
<vcsPopupProvider implementation="org.jetbrains.idea.svn17.actions.SvnQuickListContentProvider"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public enum ConflictState {
|
||||
none(false, false, false, null),
|
||||
tree(true, false, false, "/icons/conflictc.png"),
|
||||
text(false, true, false, "/icons/conflictt.png"),
|
||||
prop(false, false, true, "/icons/conflictp.png"),
|
||||
tree_text(true, true, false, "/icons/conflictct.png"), // ? -
|
||||
tree_prop(true, false, true, "/icons/conflictcp.png"), // now falls but marked
|
||||
text_prop(false, true, true, "/icons/conflicttp.png"),
|
||||
all3(true, true, true, "/icons/conflictctp.png"); // ? -
|
||||
|
||||
private final boolean myTree;
|
||||
private final boolean myText;
|
||||
private final boolean myProperty;
|
||||
@Nullable
|
||||
private final Icon myIcon;
|
||||
private final String myDescription;
|
||||
|
||||
private ConflictState(final boolean tree, final boolean text, final boolean property, final String iconPath) {
|
||||
myTree = tree;
|
||||
myText = text;
|
||||
myProperty = property;
|
||||
|
||||
if (iconPath != null) {
|
||||
myIcon = IconLoader.getIcon(iconPath);
|
||||
} else {
|
||||
myIcon = null;
|
||||
}
|
||||
|
||||
myDescription = createDescription();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String createDescription() {
|
||||
int cnt = 0;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
cnt = checkOne(myTree, cnt, sb, "tree");
|
||||
cnt = checkOne(myText, cnt, sb, "text");
|
||||
cnt = checkOne(myProperty, cnt, sb, "property");
|
||||
if (cnt == 0) {
|
||||
return null;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private int checkOne(final boolean value, final int init, final StringBuilder sb, final String text) {
|
||||
if (value) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(text);
|
||||
return init + 1;
|
||||
}
|
||||
return init;
|
||||
}
|
||||
|
||||
public boolean isTree() {
|
||||
return myTree;
|
||||
}
|
||||
|
||||
public boolean isText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public boolean isProperty() {
|
||||
return myProperty;
|
||||
}
|
||||
|
||||
public boolean isConflict() {
|
||||
return myProperty || myText || myTree;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Icon getIcon() {
|
||||
return myIcon;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
|
||||
public static ConflictState mergeState(final ConflictState leftState, final ConflictState rightState) {
|
||||
return getInstance(leftState.myTree | rightState.myTree, leftState.myText | rightState.myText,
|
||||
leftState.myProperty | rightState.myProperty);
|
||||
}
|
||||
|
||||
public static ConflictState getInstance(final boolean tree, final boolean text, final boolean property) {
|
||||
final ConflictState[] conflictStates = values();
|
||||
for (ConflictState state : conflictStates) {
|
||||
if ((state.isTree() == tree) && (state.isText() == text) && (state.isProperty() == property)) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
// all combinations are defined
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class ConflictedSvnChange extends Change {
|
||||
private final ConflictState myConflictState;
|
||||
// +-
|
||||
private final FilePath myTreeConflictMarkHolder;
|
||||
|
||||
public ConflictedSvnChange(ContentRevision beforeRevision, ContentRevision afterRevision, final ConflictState conflictState,
|
||||
final FilePath treeConflictMarkHolder) {
|
||||
super(beforeRevision, afterRevision);
|
||||
myConflictState = conflictState;
|
||||
myTreeConflictMarkHolder = treeConflictMarkHolder;
|
||||
}
|
||||
|
||||
public ConflictedSvnChange(ContentRevision beforeRevision, ContentRevision afterRevision, FileStatus fileStatus,
|
||||
final ConflictState conflictState, final FilePath treeConflictMarkHolder) {
|
||||
super(beforeRevision, afterRevision, fileStatus);
|
||||
myConflictState = conflictState;
|
||||
myTreeConflictMarkHolder = treeConflictMarkHolder;
|
||||
}
|
||||
|
||||
public ConflictState getConflictState() {
|
||||
return myConflictState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getAdditionalIcon() {
|
||||
return myConflictState.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
final String description = myConflictState.getDescription();
|
||||
if (description != null) {
|
||||
return SvnBundle.message("svn.changeview.item.in.conflict.text", description);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
public FilePath getTreeConflictMarkHolder() {
|
||||
return myTreeConflictMarkHolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public interface CopiesRefresh {
|
||||
void ensureInit();
|
||||
void asynchRequest();
|
||||
void synchRequest();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public class DefendedCopiesRefreshProxy implements CopiesRefresh {
|
||||
private final ReentranceDefence myDefence;
|
||||
|
||||
private final MyEnsureInit myEnsureInit;
|
||||
private final MyAsynchRequest myAsynchRequest;
|
||||
private final MySynchRequest mySynchRequest;
|
||||
|
||||
public DefendedCopiesRefreshProxy(final CopiesRefresh refresh) {
|
||||
myDefence = new ReentranceDefence();
|
||||
|
||||
myEnsureInit = new MyEnsureInit(refresh);
|
||||
myAsynchRequest = new MyAsynchRequest(refresh);
|
||||
mySynchRequest = new MySynchRequest(refresh);
|
||||
}
|
||||
|
||||
public void ensureInit() {
|
||||
ReentranceDefence.executeReentrant(myDefence, myEnsureInit);
|
||||
}
|
||||
|
||||
public void asynchRequest() {
|
||||
ReentranceDefence.executeReentrant(myDefence, myAsynchRequest);
|
||||
}
|
||||
|
||||
public void synchRequest() {
|
||||
ReentranceDefence.executeReentrant(myDefence, mySynchRequest);
|
||||
}
|
||||
|
||||
public Runnable proxyRefresher(final Runnable runnable) {
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
myDefence.executeOtherDefended(runnable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class MyAsynchRequest extends MyBase {
|
||||
private MyAsynchRequest(final CopiesRefresh delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public Boolean executeMe() {
|
||||
myDelegate.asynchRequest();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MySynchRequest extends MyBase {
|
||||
private MySynchRequest(final CopiesRefresh delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public Boolean executeMe() {
|
||||
myDelegate.synchRequest();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyEnsureInit extends MyBase {
|
||||
private MyEnsureInit(final CopiesRefresh delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public Boolean executeMe() {
|
||||
myDelegate.ensureInit();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class MyBase implements ReentranceDefence.MyControlled<Boolean> {
|
||||
protected final CopiesRefresh myDelegate;
|
||||
|
||||
protected MyBase(final CopiesRefresh delegate) {
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
public Boolean executeMeSimple() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class DepthCombo extends JComboBox {
|
||||
public DepthCombo(final boolean forUpdate) {
|
||||
super(forUpdate ? ourForUpdate : ourForCheckout);
|
||||
setSelectedIndex(forUpdate ? 0 : 3);
|
||||
setEditable(false);
|
||||
setToolTipText(SvnBundle.message("label.depth.description"));
|
||||
}
|
||||
|
||||
public SVNDepth getDepth() {
|
||||
return ((SVNDepthWithName) super.getSelectedItem()).getDepth();
|
||||
}
|
||||
|
||||
private final static SVNDepthWithName [] ourForUpdate = {new SVNDepthWithName(SVNDepth.UNKNOWN, "working copy"),
|
||||
new SVNDepthWithName(SVNDepth.EMPTY), new SVNDepthWithName(SVNDepth.FILES), new SVNDepthWithName(SVNDepth.IMMEDIATES),
|
||||
new SVNDepthWithName(SVNDepth.INFINITY)};
|
||||
private final static SVNDepthWithName [] ourForCheckout = {
|
||||
new SVNDepthWithName(SVNDepth.EMPTY), new SVNDepthWithName(SVNDepth.FILES), new SVNDepthWithName(SVNDepth.IMMEDIATES),
|
||||
new SVNDepthWithName(SVNDepth.INFINITY)};
|
||||
|
||||
private static class SVNDepthWithName {
|
||||
private final SVNDepth myDepth;
|
||||
private final String myName;
|
||||
|
||||
private SVNDepthWithName(SVNDepth depth) {
|
||||
myDepth = depth;
|
||||
myName = myDepth.toString();
|
||||
}
|
||||
|
||||
private SVNDepthWithName(SVNDepth depth, String name) {
|
||||
myDepth = depth;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public SVNDepth getDepth() {
|
||||
return myDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
|
||||
public class FilePathUtil {
|
||||
private FilePathUtil() {
|
||||
}
|
||||
|
||||
public static boolean isNested(final Collection<FilePath> roots, final FilePath root) {
|
||||
return isNested(roots, root.getIOFile());
|
||||
}
|
||||
|
||||
public static boolean isNested(final Collection<FilePath> roots, final File root) {
|
||||
for (FilePath filePath : roots) {
|
||||
final File ioFile = filePath.getIOFile();
|
||||
if (ioFile.equals(root)) continue;
|
||||
if (FileUtil.isAncestor(ioFile, root, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.vcs.impl.VcsRootIterator;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
import org.tmatesoft.svn.core.wc.SVNInfo;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ForNestedRootChecker {
|
||||
static class DirInfo {
|
||||
private final VirtualFile myFile;
|
||||
private final String myUrl;
|
||||
|
||||
DirInfo(final VirtualFile file, final String url) {
|
||||
myFile = file;
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UrlConstructor {
|
||||
final SvnVcs17 myVcs;
|
||||
final SVNWCClient myClient;
|
||||
|
||||
private UrlConstructor(final SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
myClient = myVcs.createWCClient();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Real createReal(final VirtualFile file, final VirtualFile vcsRoot) {
|
||||
final SVNInfo info = myVcs.getInfo(file);
|
||||
if (info == null || info.getRepositoryRootURL() == null || info.getURL() == null) {
|
||||
return null;
|
||||
}
|
||||
return new Real(file, info, vcsRoot);
|
||||
}
|
||||
|
||||
public Node createReplaceable(final VirtualFile file) {
|
||||
return new Node(file, null);
|
||||
}
|
||||
|
||||
public Node createSupposed(final Real parent, final VirtualFile child) {
|
||||
return new Node(child, getForChild(parent.getUrl(), child.getName()));
|
||||
}
|
||||
|
||||
public boolean replaceWithReal(final Real real, final Node supposed) {
|
||||
return supposed.getUrl() == null || ((supposed.getUrl() != null) && (! supposed.getUrl().equals(real.getUrl())));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getSupposedUrl(final String parentUrl, final List<String> subpath) {
|
||||
if (parentUrl == null) return null;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (String s : subpath) {
|
||||
sb.append(s).append('/');
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
return SVNPathUtil.append(parentUrl, sb.toString());
|
||||
}
|
||||
|
||||
public String getForChild(final String parentUrl, final String childName) {
|
||||
return parentUrl == null ? null : SVNPathUtil.append(parentUrl, SVNEncodingUtil.uriEncode(childName));
|
||||
}
|
||||
}
|
||||
|
||||
public static<T extends RootUrlPair> void filterOutSuperfluousChildren(final SvnVcs17 vcs, final List<T> list,
|
||||
final List<T> result) {
|
||||
final UrlConstructor constructor = new UrlConstructor(vcs);
|
||||
|
||||
Collections.sort(list, new Comparator<RootUrlPair>() {
|
||||
public int compare(final RootUrlPair o1, final RootUrlPair o2) {
|
||||
return o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath());
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final T child = list.get(i);
|
||||
boolean add = true;
|
||||
for (T parent : result) {
|
||||
if (parent.getVirtualFile().getPath().equals(child.getVirtualFile().getPath())) {
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
final List<String> subpath = subpathIfAncestor(parent.getVirtualFile(), child.getVirtualFile());
|
||||
if (subpath != null) {
|
||||
// get child's supposed and real urls
|
||||
final String supposed = constructor.getSupposedUrl(parent.getUrl(), subpath);
|
||||
if (supposed.equals(child.getUrl())) {
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<String> subpathIfAncestor(final VirtualFile parent, final VirtualFile child) {
|
||||
if (! VfsUtil.isAncestor(parent, child, true)) return null;
|
||||
|
||||
final List<String> result = new ArrayList<String>();
|
||||
VirtualFile tmp = child;
|
||||
final String parentPath = parent.getPath();
|
||||
while ((tmp != null) && (! tmp.getPath().equals(parentPath))) {
|
||||
result.add(tmp.getName());
|
||||
tmp = tmp.getParent();
|
||||
}
|
||||
Collections.reverse(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*public static List<Real> getAllNestedWorkingCopies(final VirtualFile[] roots, final SvnVcs vcs, final boolean goIntoNested) {
|
||||
if (goIntoNested) {
|
||||
FilterDescendantVirtualFiles.filter(Arrays.asList(roots));
|
||||
}
|
||||
|
||||
final VcsRootIterator rootIterator = new VcsRootIterator(vcs.getProject(), vcs);
|
||||
final List<Real> result = new ArrayList<Real>();
|
||||
for (VirtualFile root : roots) {
|
||||
result.addAll(getForOne(root, vcs, goIntoNested, rootIterator));
|
||||
}
|
||||
|
||||
if (! goIntoNested) {
|
||||
final List<Real> filtered = new ArrayList<Real>(result.size());
|
||||
filterOutSuperfluousChildren(vcs, result, filtered);
|
||||
return filtered;
|
||||
}
|
||||
|
||||
return result;
|
||||
}*/
|
||||
|
||||
public static List<Real> getAllNestedWorkingCopies(final VirtualFile root, final SvnVcs17 vcs, final boolean goIntoNested, final Getter<Boolean> cancelledGetter) {
|
||||
final VcsRootIterator rootIterator = new VcsRootIterator(vcs.getProject(), vcs);
|
||||
return getForOne(root, vcs, goIntoNested, rootIterator, cancelledGetter);
|
||||
}
|
||||
|
||||
private static List<Real> getForOne(final VirtualFile root, final SvnVcs17 vcs, final boolean goIntoNested,
|
||||
final VcsRootIterator rootIterator, final Getter<Boolean> cancelledGetter) {
|
||||
final UrlConstructor constructor = new UrlConstructor(vcs);
|
||||
final LinkedList<Node> queue = new LinkedList<Node>();
|
||||
final LinkedList<Real> result = new LinkedList<Real>();
|
||||
|
||||
queue.add(constructor.createReplaceable(root));
|
||||
while (! queue.isEmpty()) {
|
||||
final Node node = queue.removeFirst();
|
||||
if (Boolean.TRUE.equals(cancelledGetter.get())) throw new ProcessCanceledException();
|
||||
|
||||
// check self
|
||||
final Real real = constructor.createReal(node.getFile(), root);
|
||||
if (real != null) {
|
||||
if (constructor.replaceWithReal(real, node)) {
|
||||
result.add(real);
|
||||
if (! goIntoNested) continue;
|
||||
}
|
||||
}
|
||||
|
||||
// for next step
|
||||
final VirtualFile file = node.getFile();
|
||||
if (file.isDirectory() && (! SvnUtil.isAdminDirectory(file))) {
|
||||
for (VirtualFile child : file.getChildren()) {
|
||||
if (Boolean.TRUE.equals(cancelledGetter.get())) throw new ProcessCanceledException();
|
||||
if (rootIterator.acceptFolderUnderVcs(root, child)) {
|
||||
if (real == null) {
|
||||
queue.add(constructor.createReplaceable(child));
|
||||
} else {
|
||||
queue.add(constructor.createSupposed(real, child));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
public class FragmentsMerger<U, T extends Consumer<U>> {
|
||||
private T myData;
|
||||
private final Object myLock;
|
||||
private final Factory<T> myFactory;
|
||||
|
||||
public FragmentsMerger(final Factory<T> factory) {
|
||||
myFactory = factory;
|
||||
myLock = new Object();
|
||||
myData = myFactory.create();
|
||||
}
|
||||
|
||||
public void add(final U data) {
|
||||
synchronized (myLock) {
|
||||
// only T decides what to do with input, not the external code
|
||||
myData.consume(data);
|
||||
}
|
||||
}
|
||||
|
||||
public T receive() {
|
||||
synchronized (myLock) {
|
||||
final T copy = myData;
|
||||
myData = myFactory.create();
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.jetbrains.idea.svn17.config.DefaultProxyGroup;
|
||||
import org.jetbrains.idea.svn17.config.ProxyGroup;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNConfigFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class IdeaSVNConfigFile {
|
||||
private final Map<String, String> myPatternsMap;
|
||||
private final long myLatestUpdate;
|
||||
private final File myFile;
|
||||
private Map myDefaultProperties;
|
||||
|
||||
private final SVNConfigFile mySVNConfigFile;
|
||||
|
||||
private static final String GROUPS_GROUP_NAME = "groups";
|
||||
|
||||
public IdeaSVNConfigFile(final File file) {
|
||||
mySVNConfigFile = new SVNConfigFile(file);
|
||||
myFile = file;
|
||||
myLatestUpdate = -1;
|
||||
myPatternsMap = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
public void updateGroups() {
|
||||
if (myLatestUpdate != myFile.lastModified()) {
|
||||
myPatternsMap.clear();
|
||||
myPatternsMap.putAll(mySVNConfigFile.getProperties(GROUPS_GROUP_NAME));
|
||||
|
||||
myDefaultProperties = mySVNConfigFile.getProperties(DefaultProxyGroup.DEFAULT_GROUP_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, ProxyGroup> getAllGroups() {
|
||||
final Map<String, ProxyGroup> result = new HashMap<String, ProxyGroup>(myPatternsMap.size());
|
||||
for (Map.Entry<String, String> entry : myPatternsMap.entrySet()) {
|
||||
final String groupName = entry.getKey();
|
||||
result.put(groupName, new ProxyGroup(groupName, entry.getValue(), mySVNConfigFile.getProperties(groupName)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public DefaultProxyGroup getDefaultGroup() {
|
||||
return new DefaultProxyGroup(myDefaultProperties);
|
||||
}
|
||||
|
||||
public void deleteGroup(final String name) {
|
||||
// remove all properties
|
||||
final Map<String, String> properties = mySVNConfigFile.getProperties(name);
|
||||
for (String propertyName : properties.keySet()) {
|
||||
mySVNConfigFile.setPropertyValue(name, propertyName, null, false);
|
||||
}
|
||||
if (DefaultProxyGroup.DEFAULT_GROUP_NAME.equals(name)) {
|
||||
myDefaultProperties.clear();
|
||||
}
|
||||
// remove group from groups
|
||||
mySVNConfigFile.setPropertyValue(GROUPS_GROUP_NAME, name, null, false);
|
||||
mySVNConfigFile.deleteGroup(name, false);
|
||||
}
|
||||
|
||||
public void addGroup(final String name, final String patterns, final Map<String, String> properties) {
|
||||
mySVNConfigFile.setPropertyValue(GROUPS_GROUP_NAME, name, patterns, false);
|
||||
addProperties(name, properties);
|
||||
}
|
||||
|
||||
private void addProperties(final String groupName, final Map<String, String> properties) {
|
||||
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
||||
mySVNConfigFile.setPropertyValue(groupName, entry.getKey(), entry.getValue(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyGroup(final String name, final String patterns, final Collection<String> delete, final Map<String, String> addOrModify,
|
||||
final boolean isDefault) {
|
||||
if (! isDefault) {
|
||||
mySVNConfigFile.setPropertyValue(GROUPS_GROUP_NAME, name, patterns, false);
|
||||
}
|
||||
final Map<String,String> deletedPrepared = new HashMap<String, String>(delete.size());
|
||||
for (String property : delete) {
|
||||
deletedPrepared.put(property, null);
|
||||
}
|
||||
addProperties(name, deletedPrepared);
|
||||
addProperties(name, addOrModify);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
mySVNConfigFile.save();
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class IdeaSubversionConfigurationDirectory {
|
||||
private IdeaSubversionConfigurationDirectory() {
|
||||
}
|
||||
|
||||
public static String getPath() {
|
||||
final File standard = SVNWCUtil.getDefaultConfigurationDirectory();
|
||||
if (SystemInfo.isWindows) {
|
||||
return standard.getAbsolutePath();
|
||||
}
|
||||
return standard.getParent() + File.separator + standard.getName() + "_IDEA";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
|
||||
import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class IgnoredFileInfo {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.IgnoredFileInfo");
|
||||
|
||||
// directory for which properties are collected
|
||||
private final File myFile;
|
||||
private final List<String> myPatterns;
|
||||
private final Set<String> myFileNames;
|
||||
private final Set<String> myOldPatterns;
|
||||
|
||||
public IgnoredFileInfo(final File file, final Set<String> oldPatterns) {
|
||||
myFile = file;
|
||||
myPatterns = new ArrayList<String>();
|
||||
myFileNames = new HashSet<String>();
|
||||
myOldPatterns = oldPatterns;
|
||||
}
|
||||
|
||||
public void addFileName(final String name) {
|
||||
myFileNames.add(name);
|
||||
}
|
||||
|
||||
public void addPattern(final String value) {
|
||||
myPatterns.add(value);
|
||||
}
|
||||
|
||||
public void calculatePatterns(final SvnVcs17 vcs) {
|
||||
final List<String> names = new ArrayList<String>();
|
||||
try {
|
||||
vcs.createStatusClient().doStatus(myFile, SVNRevision.WORKING, SVNDepth.IMMEDIATES, false, true, true, false, new ISVNStatusHandler() {
|
||||
public void handleStatus(SVNStatus status) throws SVNException {
|
||||
if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_IGNORED)) {
|
||||
final String name = status.getFile().getName();
|
||||
if (! myFileNames.contains(name)) {
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
|
||||
for (String pattern : myOldPatterns) {
|
||||
boolean usedSomewhereElse = false;
|
||||
for (String name : names) {
|
||||
if (DefaultSVNOptions.matches(pattern, name)) {
|
||||
usedSomewhereElse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! usedSomewhereElse) {
|
||||
for (String name : myFileNames) {
|
||||
if (DefaultSVNOptions.matches(pattern, name)) {
|
||||
myPatterns.add(pattern);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public List<String> getPatterns() {
|
||||
return myPatterns;
|
||||
}
|
||||
|
||||
public Set<String> getFileNames() {
|
||||
return myFileNames;
|
||||
}
|
||||
|
||||
public Set<String> getOldPatterns() {
|
||||
return myOldPatterns;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LimitedStringsList {
|
||||
private static final int ourMaxTypedUrls = 20;
|
||||
private final List<String> myList;
|
||||
|
||||
public LimitedStringsList(final List<String> list) {
|
||||
myList = new ArrayList<String>((list.size() > ourMaxTypedUrls ? list.subList(0, ourMaxTypedUrls) : list));
|
||||
}
|
||||
|
||||
public void add(final String value) {
|
||||
myList.remove(value);
|
||||
|
||||
if (myList.size() >= ourMaxTypedUrls) {
|
||||
// leave space for 1 to be added
|
||||
final int numToRemove = myList.size() - ourMaxTypedUrls + 1;
|
||||
for (int i = 0; i < numToRemove; i++) {
|
||||
myList.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
// more recent first
|
||||
myList.add(0, value);
|
||||
}
|
||||
|
||||
public List<String> getList() {
|
||||
return Collections.unmodifiableList(myList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
|
||||
public class MoveRenameReplaceCheck {
|
||||
public static boolean check(final Change c) {
|
||||
if (c.getAfterRevision() == null || c.getBeforeRevision() == null) return false;
|
||||
return c.isIsReplaced() || c.isMoved() || c.isRenamed() || (! Comparing.equal(c.getBeforeRevision().getFile(), c.getAfterRevision().getFile()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class NestedCopiesBuilder implements StatusReceiver {
|
||||
private final Set<MyPointInfo> mySet;
|
||||
|
||||
public NestedCopiesBuilder() {
|
||||
mySet = new HashSet<MyPointInfo>();
|
||||
}
|
||||
|
||||
public void process(final FilePath path, final SVNStatus status, final boolean isInnerCopyRoot) throws SVNException {
|
||||
if ((path.getVirtualFile() != null) && SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_EXTERNAL)) {
|
||||
final MyPointInfo info = new MyPointInfo(path.getVirtualFile(), null, WorkingCopyFormat.UNKNOWN, NestedCopyType.external);
|
||||
mySet.add(info);
|
||||
return;
|
||||
}
|
||||
if ((path.getVirtualFile() == null) || (status.getURL() == null)) return;
|
||||
|
||||
final NestedCopyType type;
|
||||
if (SvnVcs17.svnStatusIsUnversioned(status)) {
|
||||
return;
|
||||
} else if (status.isSwitched()) {
|
||||
type = NestedCopyType.switched;
|
||||
} else if (isInnerCopyRoot) {
|
||||
// will not be changed or modified; can't be switched or external
|
||||
type = NestedCopyType.inner;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
final MyPointInfo info = new MyPointInfo(path.getVirtualFile(), status.getURL(),
|
||||
WorkingCopyFormat.getInstance(status.getWorkingCopyFormat()), type);
|
||||
mySet.add(info);
|
||||
}
|
||||
|
||||
public void processIgnored(final VirtualFile vFile) {
|
||||
}
|
||||
|
||||
public void processUnversioned(final VirtualFile vFile) {
|
||||
}
|
||||
|
||||
static class MyPointInfo {
|
||||
private final VirtualFile myFile;
|
||||
private SVNURL myUrl;
|
||||
private WorkingCopyFormat myFormat;
|
||||
private final NestedCopyType myType;
|
||||
|
||||
MyPointInfo(@NotNull final VirtualFile file, final SVNURL url, final WorkingCopyFormat format, final NestedCopyType type) {
|
||||
myFile = file;
|
||||
myUrl = url;
|
||||
myFormat = format;
|
||||
myType = type;
|
||||
}
|
||||
|
||||
public void setUrl(SVNURL url) {
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
public void setFormat(WorkingCopyFormat format) {
|
||||
myFormat = format;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public WorkingCopyFormat getFormat() {
|
||||
return myFormat;
|
||||
}
|
||||
|
||||
public NestedCopyType getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
private String key(final VirtualFile file) {
|
||||
return file.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
MyPointInfo info = (MyPointInfo)o;
|
||||
|
||||
if (! key(myFile).equals(key(info.myFile))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return key(myFile).hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<MyPointInfo> getSet() {
|
||||
return mySet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class NestedCopiesData implements Consumer<Set<NestedCopiesBuilder.MyPointInfo>> {
|
||||
// we can keep the type here also, but
|
||||
private final Set<NestedCopiesBuilder.MyPointInfo> mySet;
|
||||
|
||||
public NestedCopiesData() {
|
||||
mySet = new HashSet<NestedCopiesBuilder.MyPointInfo>();
|
||||
}
|
||||
|
||||
public void consume(final Set<NestedCopiesBuilder.MyPointInfo> nestedCopyTypeSet) {
|
||||
mySet.addAll(nestedCopyTypeSet);
|
||||
}
|
||||
|
||||
public Set<NestedCopiesBuilder.MyPointInfo> getSet() {
|
||||
return mySet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class NestedCopiesSink extends FragmentsMerger<Set<NestedCopiesBuilder.MyPointInfo>, NestedCopiesData> {
|
||||
public NestedCopiesSink() {
|
||||
super(new Factory<NestedCopiesData>() {
|
||||
public NestedCopiesData create() {
|
||||
return new NestedCopiesData();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public enum NestedCopyType {
|
||||
external("External"),
|
||||
switched("Switched"),
|
||||
inner("Nested");
|
||||
|
||||
private final String myName;
|
||||
|
||||
NestedCopyType(String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
class Node {
|
||||
private final VirtualFile myFile;
|
||||
private final String myUrl;
|
||||
|
||||
Node(final VirtualFile file, final String url) {
|
||||
myFile = file;
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.tmatesoft.svn.core.auth.*;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 1/24/11
|
||||
* Time: 6:14 PM
|
||||
*/
|
||||
public class ProxySvnAuthentication {
|
||||
private ProxySvnAuthentication() {
|
||||
}
|
||||
|
||||
public static SVNAuthentication proxy(final SVNAuthentication in, final boolean storeAuth) {
|
||||
if (in.isStorageAllowed() == storeAuth || (! in.isStorageAllowed())) return in;
|
||||
|
||||
final String userName = in.getUserName();
|
||||
if (in instanceof SVNPasswordAuthentication) {
|
||||
return new SVNPasswordAuthentication(userName, ((SVNPasswordAuthentication)in).getPassword(),
|
||||
storeAuth, in.getURL(), in.isPartial());
|
||||
} else if (in instanceof SVNSSHAuthentication) {
|
||||
final SVNSSHAuthentication svnsshAuthentication = (SVNSSHAuthentication)in;
|
||||
if (svnsshAuthentication.hasPrivateKey()) {
|
||||
return new SVNSSHAuthentication(userName, svnsshAuthentication.getPrivateKeyFile(), svnsshAuthentication.getPassphrase(),
|
||||
svnsshAuthentication.getPortNumber(), storeAuth, in.getURL(), in.isPartial());
|
||||
} else {
|
||||
return new SVNSSHAuthentication(userName, svnsshAuthentication.getPassword(), svnsshAuthentication.getPortNumber(),
|
||||
storeAuth, in.getURL(), in.isPartial());
|
||||
}
|
||||
} else if (in instanceof SVNSSLAuthentication) {
|
||||
final SVNSSLAuthentication svnsslAuthentication = (SVNSSLAuthentication)in;
|
||||
if (SVNSSLAuthentication.MSCAPI.equals(svnsslAuthentication.getSSLKind())) {
|
||||
return new SVNSSLAuthentication(SVNSSLAuthentication.MSCAPI, svnsslAuthentication.getAlias(), storeAuth, in.getURL(), in.isPartial());
|
||||
} else {
|
||||
return new SVNSSLAuthentication(svnsslAuthentication.getCertificateFile(), svnsslAuthentication.getPassword(),
|
||||
storeAuth, svnsslAuthentication.getURL(), svnsslAuthentication.isPartial());
|
||||
}
|
||||
} else if (in instanceof SVNUserNameAuthentication) {
|
||||
return new SVNUserNameAuthentication(in.getUserName(), storeAuth, in.getURL(), in.isPartial());
|
||||
}
|
||||
return in;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.wc.SVNInfo;
|
||||
|
||||
class Real extends Node implements RootUrlPair {
|
||||
private final SVNInfo myInfo;
|
||||
private final VirtualFile myVcsRoot;
|
||||
|
||||
Real(final VirtualFile file, final SVNInfo info, VirtualFile vcsRoot) {
|
||||
super(file, info.getURL().toString());
|
||||
myInfo = info;
|
||||
myVcsRoot = vcsRoot;
|
||||
}
|
||||
|
||||
public SVNInfo getInfo() {
|
||||
return myInfo;
|
||||
}
|
||||
|
||||
public VirtualFile getVcsRoot() {
|
||||
return myVcsRoot;
|
||||
}
|
||||
|
||||
public VirtualFile getVirtualFile() {
|
||||
return getFile();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public class ReentranceDefence {
|
||||
protected final ThreadLocal<Boolean> myThreadLocal;
|
||||
|
||||
protected ReentranceDefence() {
|
||||
myThreadLocal = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> T executeReentrant(final ReentranceDefence defence, final MyControlled<T> controlled) {
|
||||
if (defence.isInside()) {
|
||||
return controlled.executeMeSimple();
|
||||
}
|
||||
return controlled.executeMe();
|
||||
}
|
||||
|
||||
public boolean isInside() {
|
||||
return ! Boolean.TRUE.equals(myThreadLocal.get());
|
||||
}
|
||||
|
||||
public boolean isOutside() {
|
||||
return ! isInside();
|
||||
}
|
||||
|
||||
public void executeOtherDefended(final Runnable runnable) {
|
||||
try {
|
||||
myThreadLocal.set(Boolean.FALSE);
|
||||
runnable.run();
|
||||
} finally {
|
||||
myThreadLocal.set(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
public interface MyControlled<T> {
|
||||
T executeMe();
|
||||
T executeMeSimple();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
public class RootMixedInfo {
|
||||
/**
|
||||
* working copy root path
|
||||
*/
|
||||
private final String myFilePath;
|
||||
private final VirtualFile myFile;
|
||||
/**
|
||||
* url corresponding to working copy root
|
||||
*/
|
||||
private final SVNURL myUrl;
|
||||
private final VirtualFile myParentVcsRoot;
|
||||
|
||||
public RootMixedInfo(final String filePath, final VirtualFile file, final SVNURL url, final VirtualFile parentVcsRoot) {
|
||||
myFilePath = filePath;
|
||||
myFile = file;
|
||||
myUrl = url;
|
||||
myParentVcsRoot = parentVcsRoot;
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public VirtualFile getParentVcsRoot() {
|
||||
return myParentVcsRoot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class RootUrlInfo implements RootUrlPair {
|
||||
private final SVNURL myRepositoryUrlUrl;
|
||||
private final String myRepositoryUrl;
|
||||
private final SVNURL myAbsoluteUrlAsUrl;
|
||||
private final WorkingCopyFormat myFormat;
|
||||
|
||||
private final File myIoFile;
|
||||
private final VirtualFile myVfile;
|
||||
// vcs root
|
||||
private final VirtualFile myRoot;
|
||||
private NestedCopyType myType;
|
||||
|
||||
public RootUrlInfo(final SVNURL repositoryUrl, final SVNURL absoluteUrlAsUrl, final WorkingCopyFormat format, final VirtualFile vfile,
|
||||
final VirtualFile root) {
|
||||
myRepositoryUrlUrl = repositoryUrl;
|
||||
myFormat = format;
|
||||
myVfile = vfile;
|
||||
myRoot = root;
|
||||
myIoFile = new File(myVfile.getPath());
|
||||
final String asString = repositoryUrl.toString();
|
||||
myRepositoryUrl = asString.endsWith("/") ? asString.substring(0, asString.length() - 1) : asString;
|
||||
myAbsoluteUrlAsUrl = absoluteUrlAsUrl;
|
||||
//myType = NestedCopyType.inner; // default
|
||||
}
|
||||
|
||||
public String getRepositoryUrl() {
|
||||
return myRepositoryUrl;
|
||||
}
|
||||
|
||||
public SVNURL getRepositoryUrlUrl() {
|
||||
return myRepositoryUrlUrl;
|
||||
}
|
||||
|
||||
public String getAbsoluteUrl() {
|
||||
return myAbsoluteUrlAsUrl.toString();
|
||||
}
|
||||
|
||||
public SVNURL getAbsoluteUrlAsUrl() {
|
||||
return myAbsoluteUrlAsUrl;
|
||||
}
|
||||
|
||||
public WorkingCopyFormat getFormat() {
|
||||
return myFormat;
|
||||
}
|
||||
|
||||
public File getIoFile() {
|
||||
return myIoFile;
|
||||
}
|
||||
|
||||
// vcs root
|
||||
public VirtualFile getRoot() {
|
||||
return myRoot;
|
||||
}
|
||||
|
||||
public VirtualFile getVirtualFile() {
|
||||
return myVfile;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myAbsoluteUrlAsUrl.toString();
|
||||
}
|
||||
|
||||
public NestedCopyType getType() {
|
||||
return myType;
|
||||
}
|
||||
|
||||
public void setType(NestedCopyType type) {
|
||||
myType = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
public interface RootUrlPair {
|
||||
VirtualFile getVirtualFile();
|
||||
String getUrl();
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.BackgroundTaskQueue;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInBackground;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsListener;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
|
||||
import org.tmatesoft.svn.core.wc.SVNInfo;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
// 1. listen to roots changes
|
||||
// 2. - possibly - to deletion/checkouts??? what if WC roots can be
|
||||
public class RootsToWorkingCopies implements VcsListener {
|
||||
private final Object myLock;
|
||||
private final Map<VirtualFile, WorkingCopy> myRootMapping;
|
||||
private final Set<VirtualFile> myUnversioned;
|
||||
private final BackgroundTaskQueue myQueue;
|
||||
private final Project myProject;
|
||||
|
||||
public RootsToWorkingCopies(final Project project) {
|
||||
myProject = project;
|
||||
myQueue = new BackgroundTaskQueue(project, "SVN VCS roots authorization checker");
|
||||
myLock = new Object();
|
||||
myRootMapping = new HashMap<VirtualFile, WorkingCopy>();
|
||||
myUnversioned = new HashSet<VirtualFile>();
|
||||
}
|
||||
|
||||
public void addRoot(final VirtualFile root) {
|
||||
myQueue.run(new Task.Backgroundable(myProject, "Looking for '" + root.getPath() + "' working copy root", false,
|
||||
BackgroundFromStartOption.getInstance()) {
|
||||
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
calculateRoot(root);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@CalledInBackground
|
||||
public WorkingCopy getMatchingCopy(final SVNURL url) {
|
||||
assert ! ApplicationManager.getApplication().isDispatchThread();
|
||||
|
||||
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(SvnVcs17.getInstance(myProject));
|
||||
synchronized (myLock) {
|
||||
for (VirtualFile root : roots) {
|
||||
final WorkingCopy wcRoot = getWcRoot(root);
|
||||
if (wcRoot != null) {
|
||||
final SVNURL common = SVNURLUtil.getCommonURLAncestor(wcRoot.getUrl(), url);
|
||||
if (wcRoot.getUrl().equals(common) || url.equals(common)) {
|
||||
return wcRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@CalledInBackground
|
||||
@Nullable
|
||||
public WorkingCopy getWcRoot(final VirtualFile root) {
|
||||
assert ! ApplicationManager.getApplication().isDispatchThread();
|
||||
|
||||
synchronized (myLock) {
|
||||
if (myUnversioned.contains(root)) return null;
|
||||
final WorkingCopy existing = myRootMapping.get(root);
|
||||
if (existing != null) return existing;
|
||||
}
|
||||
return calculateRoot(root);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private WorkingCopy calculateRoot(final VirtualFile root) {
|
||||
WorkingCopy workingCopy = null;
|
||||
final File ioFile = new File(root.getPath());
|
||||
File workingCopyRoot = null;
|
||||
try {
|
||||
workingCopyRoot = SVNWCUtil.getWorkingCopyRoot(ioFile, true);
|
||||
if (workingCopyRoot != null) {
|
||||
SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
|
||||
try {
|
||||
wcAccess.probeOpen(workingCopyRoot, false, 0);
|
||||
SVNEntry entry = wcAccess.getVersionedEntry(workingCopyRoot, false);
|
||||
final SVNURL url = entry.getSVNURL();
|
||||
if (url != null) {
|
||||
workingCopy = new WorkingCopy(workingCopyRoot, url);
|
||||
}
|
||||
} finally {
|
||||
wcAccess.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
if (workingCopyRoot == null) {
|
||||
workingCopyRoot = SvnUtil.getWcCopyRootIf17(ioFile, null);
|
||||
if (workingCopyRoot != null) {
|
||||
final SVNInfo svnInfo;
|
||||
try {
|
||||
svnInfo = SvnVcs17.getInstance(myProject).createWCClient().doInfo(workingCopyRoot, SVNRevision.UNDEFINED);
|
||||
workingCopy = new WorkingCopy(workingCopyRoot, svnInfo.getURL());
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized (myLock) {
|
||||
if (workingCopy == null) {
|
||||
myRootMapping.remove(root);
|
||||
myUnversioned.add(root);
|
||||
} else {
|
||||
myUnversioned.remove(root);
|
||||
myRootMapping.put(root, workingCopy);
|
||||
}
|
||||
}
|
||||
return workingCopy;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
synchronized (myLock) {
|
||||
myRootMapping.clear();
|
||||
myUnversioned.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void directoryMappingChanged() {
|
||||
final SvnVcs17 svnVcs = SvnVcs17.getInstance(myProject);
|
||||
// todo +- here... shouldnt be
|
||||
svnVcs.getAuthNotifier().clear();
|
||||
|
||||
final VirtualFile[] roots = ProjectLevelVcsManager.getInstance(myProject).getRootsUnderVcs(svnVcs);
|
||||
synchronized (myLock) {
|
||||
clear();
|
||||
for (VirtualFile root : roots) {
|
||||
addRoot(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
public interface StatusReceiver extends EventListener {
|
||||
void process(final FilePath path, final SVNStatus status, final boolean isInnerCopyRoot) throws SVNException;
|
||||
void processIgnored(final VirtualFile vFile);
|
||||
void processUnversioned(final VirtualFile vFile);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusClient;
|
||||
|
||||
public interface StatusWalkerPartner {
|
||||
SVNStatusClient createStatusClient();
|
||||
void checkCanceled();
|
||||
boolean isExcluded(final VirtualFile vFile);
|
||||
boolean isIgnoredIdeaLevel(final VirtualFile vFile);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.roots.FileIndexFacade;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.SVNCancelException;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider;
|
||||
import org.tmatesoft.svn.core.wc.SVNEvent;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusClient;
|
||||
|
||||
public class StatusWalkerPartnerImpl implements StatusWalkerPartner {
|
||||
private final SvnVcs17 myVcs;
|
||||
private final ChangeListManager myClManager;
|
||||
private final FileIndexFacade myExcludedFileIndex;
|
||||
private final ProgressIndicator myIndicator;
|
||||
private ISVNStatusFileProvider myFileProvider;
|
||||
|
||||
public StatusWalkerPartnerImpl(final SvnVcs17 vcs, final ProgressIndicator pi) {
|
||||
myVcs = vcs;
|
||||
myClManager = ChangeListManager.getInstance(myVcs.getProject());
|
||||
myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(myVcs.getProject(), FileIndexFacade.class);
|
||||
myIndicator = pi;
|
||||
}
|
||||
|
||||
public void setFileProvider(final ISVNStatusFileProvider fileProvider) {
|
||||
myFileProvider = fileProvider;
|
||||
}
|
||||
|
||||
public SVNStatusClient createStatusClient() {
|
||||
final SVNStatusClient result = myVcs.createStatusClient();
|
||||
result.setFilesProvider(myFileProvider);
|
||||
result.setEventHandler(new ISVNEventHandler() {
|
||||
public void handleEvent(SVNEvent event, double progress) throws SVNException {
|
||||
//
|
||||
}
|
||||
|
||||
public void checkCancelled() throws SVNCancelException {
|
||||
if (myIndicator != null) {
|
||||
myIndicator.checkCanceled();
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public void checkCanceled() {
|
||||
if (myIndicator != null) {
|
||||
myIndicator.checkCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExcluded(VirtualFile vFile) {
|
||||
return myExcludedFileIndex.isExcludedFile(vFile);
|
||||
}
|
||||
|
||||
public boolean isIgnoredIdeaLevel(VirtualFile vFile) {
|
||||
return myClManager.isIgnoredFile(vFile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@State(
|
||||
name="SvnApplicationSettings17",
|
||||
storages = {
|
||||
@Storage(
|
||||
file="$APP_CONFIG$/other.xml"
|
||||
)}
|
||||
)
|
||||
public class SvnApplicationSettings17 implements PersistentStateComponent<SvnApplicationSettings17.ConfigurationBean> {
|
||||
private SvnFileSystemListenerWrapper myVFSHandler;
|
||||
private int mySvnProjectCount;
|
||||
private LimitedStringsList myLimitedStringsList;
|
||||
|
||||
public static class ConfigurationBean {
|
||||
public List<String> myCheckoutURLs = new ArrayList<String>();
|
||||
public List<String> myTypedURLs = new ArrayList<String>();
|
||||
}
|
||||
|
||||
private ConfigurationBean myConfigurationBean;
|
||||
|
||||
public static SvnApplicationSettings17 getInstance() {
|
||||
return ServiceManager.getService(SvnApplicationSettings17.class);
|
||||
}
|
||||
|
||||
public SvnApplicationSettings17() {
|
||||
myConfigurationBean = new ConfigurationBean();
|
||||
}
|
||||
|
||||
public ConfigurationBean getState() {
|
||||
myConfigurationBean.myTypedURLs.clear();
|
||||
myConfigurationBean.myTypedURLs.addAll(getTypedList().getList());
|
||||
return myConfigurationBean;
|
||||
}
|
||||
|
||||
public void loadState(ConfigurationBean object) {
|
||||
myConfigurationBean = object;
|
||||
getTypedList();
|
||||
}
|
||||
|
||||
private LimitedStringsList getTypedList() {
|
||||
if (myLimitedStringsList == null) {
|
||||
checkFillTypedFromCheckout();
|
||||
myLimitedStringsList = new LimitedStringsList(myConfigurationBean.myTypedURLs);
|
||||
}
|
||||
return myLimitedStringsList;
|
||||
}
|
||||
|
||||
private void checkFillTypedFromCheckout() {
|
||||
if (myConfigurationBean.myTypedURLs.isEmpty() && (! myConfigurationBean.myCheckoutURLs.isEmpty())) {
|
||||
myConfigurationBean.myTypedURLs.addAll(myConfigurationBean.myCheckoutURLs);
|
||||
}
|
||||
}
|
||||
|
||||
public void svnActivated() {
|
||||
if (myVFSHandler == null) {
|
||||
myVFSHandler = new SvnFileSystemListenerWrapper(new SvnFileSystemListener());
|
||||
myVFSHandler.registerSelf();
|
||||
}
|
||||
mySvnProjectCount++;
|
||||
}
|
||||
|
||||
public void svnDeactivated() {
|
||||
mySvnProjectCount--;
|
||||
if (mySvnProjectCount == 0) {
|
||||
myVFSHandler.unregisterSelf();
|
||||
myVFSHandler = null;
|
||||
// todo what should be done instead?
|
||||
//SVNSSHSession.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private static File getCommonPath() {
|
||||
File file = new File(PathManager.getSystemPath());
|
||||
file = new File(file, "plugins");
|
||||
file = new File(file, "svn4idea17");
|
||||
file.mkdirs();
|
||||
return file;
|
||||
}
|
||||
|
||||
public static File getCredentialsFile() {
|
||||
return new File(getCommonPath(), "credentials.xml");
|
||||
}
|
||||
|
||||
private static final String LOADED_REVISIONS_DIR = "loadedRevisions";
|
||||
|
||||
public static File getLoadedRevisionsDir(final Project project) {
|
||||
File file = getCommonPath();
|
||||
file = new File(file, LOADED_REVISIONS_DIR);
|
||||
file = new File(file, project.getLocationHash());
|
||||
file.mkdirs();
|
||||
return file;
|
||||
}
|
||||
|
||||
public Collection<String> getCheckoutURLs() {
|
||||
return myConfigurationBean.myCheckoutURLs;
|
||||
}
|
||||
|
||||
public void addCheckoutURL(String url) {
|
||||
if (myConfigurationBean.myCheckoutURLs.contains(url)) {
|
||||
return;
|
||||
}
|
||||
myConfigurationBean.myCheckoutURLs.add(0, url);
|
||||
}
|
||||
|
||||
public void removeCheckoutURL(String url) {
|
||||
if (myConfigurationBean.myCheckoutURLs != null) {
|
||||
// 'url' is not necessary an exact match for some of the urls in collection - it has been parsed and then converted back to string
|
||||
for(String oldUrl: myConfigurationBean.myCheckoutURLs) {
|
||||
try {
|
||||
if (url.equals(oldUrl) || SVNURL.parseURIEncoded(url).equals(SVNURL.parseURIEncoded(oldUrl))) {
|
||||
myConfigurationBean.myCheckoutURLs.remove(oldUrl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getTypedUrlsListCopy() {
|
||||
return new ArrayList<String>(getTypedList().getList());
|
||||
}
|
||||
|
||||
public void addTypedUrl(final String url) {
|
||||
getTypedList().add(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import org.tmatesoft.svn.core.auth.*;
|
||||
|
||||
public class SvnAuthEquals {
|
||||
private SvnAuthEquals() {
|
||||
}
|
||||
|
||||
public static boolean equals(final SVNAuthentication a1, final SVNAuthentication a2) {
|
||||
if (a1 == a2) return true;
|
||||
if (a1 == null || a2 == null) return false;
|
||||
if (! Comparing.equal(a1.getKind(), a2.getKind())) return false;
|
||||
if (! Comparing.equal(a1.getUserName(), a2.getUserName())) return false;
|
||||
|
||||
final Class<? extends SVNAuthentication> a1Class = a1.getClass();
|
||||
if (! a1Class.equals(a2.getClass())) return false;
|
||||
|
||||
if (SVNUserNameAuthentication.class.equals(a1Class)) return true;
|
||||
if (SVNPasswordAuthentication.class.equals(a1Class)) {
|
||||
return Comparing.equal(((SVNPasswordAuthentication) a1).getPassword(), ((SVNPasswordAuthentication) a2).getPassword());
|
||||
}
|
||||
if (SVNSSLAuthentication.class.equals(a1Class)) {
|
||||
if (! Comparing.equal(((SVNSSLAuthentication) a1).getCertificateFile(), ((SVNSSLAuthentication) a2).getCertificateFile())) return false;
|
||||
return Comparing.equal(((SVNSSLAuthentication) a1).getPassword(), ((SVNSSLAuthentication) a2).getPassword());
|
||||
}
|
||||
if (SVNSSHAuthentication.class.equals(a1Class)) {
|
||||
if (! Comparing.equal(((SVNSSHAuthentication) a1).getPrivateKeyFile(), ((SVNSSHAuthentication) a2).getPrivateKeyFile())) return false;
|
||||
if (! Comparing.equal(((SVNSSHAuthentication) a1).getPassphrase(), ((SVNSSHAuthentication) a2).getPassphrase())) return false;
|
||||
if (! Comparing.equal(((SVNSSHAuthentication) a1).getPortNumber(), ((SVNSSHAuthentication) a2).getPortNumber())) return false;
|
||||
return Comparing.equal(((SVNSSHAuthentication) a1).getPassword(), ((SVNSSHAuthentication) a2).getPassword());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int hashCode(final SVNAuthentication a) {
|
||||
int result = a.getKind().hashCode();
|
||||
if (a.getUserName() != null) {
|
||||
result = (31 * result) + a.getUserName().hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,825 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vcs.changes.committed.AbstractCalledLater;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.auth.ProviderType;
|
||||
import org.jetbrains.idea.svn17.auth.SvnAuthenticationInteraction;
|
||||
import org.jetbrains.idea.svn17.auth.SvnAuthenticationListener;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNProperties;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.auth.*;
|
||||
import org.tmatesoft.svn.core.internal.wc.*;
|
||||
import org.tmatesoft.svn.core.io.SVNRepository;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author alex
|
||||
*/
|
||||
public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager implements SvnAuthenticationListener {
|
||||
// while Mac storage not working for IDEA, we use this key to check whether to prompt abt plaintext or just store
|
||||
private static final Logger LOG = Logger.getInstance(SvnAuthenticationManager.class.getName());
|
||||
public static final String SVN_SSH = "svn+ssh";
|
||||
public static final String HTTP = "http";
|
||||
public static final String HTTPS = "https";
|
||||
private final Project myProject;
|
||||
private File myConfigDirectory;
|
||||
private PersistentAuthenticationProviderProxy myPersistentAuthenticationProviderProxy;
|
||||
private SvnConfiguration17 myConfig;
|
||||
private static final ThreadLocal<Boolean> ourJustEntered = new ThreadLocal<Boolean>();
|
||||
private SvnAuthenticationInteraction myInteraction;
|
||||
private EventDispatcher<SvnAuthenticationListener> myListener;
|
||||
private IdeaSVNHostOptionsProvider myLocalHostOptionsProvider;
|
||||
private final ThreadLocalSavePermissions mySavePermissions;
|
||||
private final Map<Thread, String> myKeyAlgorithm;
|
||||
|
||||
public SvnAuthenticationManager(final Project project, final File configDirectory) {
|
||||
super(configDirectory, true, null, null);
|
||||
myProject = project;
|
||||
myConfigDirectory = configDirectory;
|
||||
myKeyAlgorithm = new HashMap<Thread, String>();
|
||||
ensureListenerCreated();
|
||||
mySavePermissions = new ThreadLocalSavePermissions();
|
||||
myConfig = SvnConfiguration17.getInstance(myProject);
|
||||
if (myPersistentAuthenticationProviderProxy != null) {
|
||||
myPersistentAuthenticationProviderProxy.setProject(myProject);
|
||||
}
|
||||
myInteraction = new MySvnAuthenticationInteraction(myProject);
|
||||
}
|
||||
|
||||
private void ensureListenerCreated() {
|
||||
if (myListener == null) {
|
||||
myListener = EventDispatcher.create(SvnAuthenticationListener.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdeaSVNHostOptionsProvider getHostOptionsProvider() {
|
||||
if (myLocalHostOptionsProvider == null) {
|
||||
myLocalHostOptionsProvider = new IdeaSVNHostOptionsProvider();
|
||||
}
|
||||
return myLocalHostOptionsProvider;
|
||||
}
|
||||
|
||||
public void addListener(final SvnAuthenticationListener listener) {
|
||||
myListener.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actualSaveWillBeTried(ProviderType type, SVNURL url, String realm, String kind) {
|
||||
myListener.getMulticaster().actualSaveWillBeTried(type, url, realm, kind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAttemptStarted(ProviderType type, SVNURL url, String realm, String kind) {
|
||||
myListener.getMulticaster().saveAttemptStarted(type, url, realm, kind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAttemptFinished(ProviderType type, SVNURL url, String realm, String kind) {
|
||||
myListener.getMulticaster().saveAttemptFinished(type, url, realm, kind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requested(ProviderType type, SVNURL url, String realm, String kind, boolean canceled) {
|
||||
if (ProviderType.interactive.equals(type) && (! canceled)) {
|
||||
ourJustEntered.set(true);
|
||||
}
|
||||
myListener.getMulticaster().requested(type, url, realm, kind, canceled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ISVNAuthenticationProvider createCacheAuthenticationProvider(File authDir, String userName) {
|
||||
// this is a hack due to the fact this method is called from super() constructor
|
||||
myConfigDirectory = new File(authDir.getParent());
|
||||
myPersistentAuthenticationProviderProxy = new PersistentAuthenticationProviderProxy(authDir, userName);
|
||||
return myPersistentAuthenticationProviderProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acknowledgeAuthentication(boolean accepted,
|
||||
String kind,
|
||||
String realm,
|
||||
SVNErrorMessage errorMessage,
|
||||
SVNAuthentication authentication) throws SVNException {
|
||||
try {
|
||||
final boolean authStorageEnabled = getHostOptionsProvider().getHostOptions(authentication.getURL()).isAuthStorageEnabled();
|
||||
final SVNAuthentication proxy = ProxySvnAuthentication.proxy(authentication, authStorageEnabled);
|
||||
super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, proxy);
|
||||
} finally {
|
||||
mySavePermissions.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private class PersistentAuthenticationProviderProxy implements ISVNAuthenticationProvider, ISVNPersistentAuthenticationProvider {
|
||||
private final ISVNAuthenticationProvider myDelegate;
|
||||
private final ISVNGnomeKeyringPasswordProvider myISVNGnomeKeyringPasswordProvider;
|
||||
private final File myAuthDir;
|
||||
private Project myProject;
|
||||
|
||||
private PersistentAuthenticationProviderProxy(File authDir, String userName) {
|
||||
myISVNGnomeKeyringPasswordProvider = new MyKeyringMasterKeyProvider(myProject);
|
||||
ISVNAuthenticationStorageOptions delegatingOptions = new ISVNAuthenticationStorageOptions() {
|
||||
public boolean isNonInteractive() throws SVNException {
|
||||
return getAuthenticationStorageOptions().isNonInteractive();
|
||||
}
|
||||
|
||||
public ISVNAuthStoreHandler getAuthStoreHandler() throws SVNException {
|
||||
return getAuthenticationStorageOptions().getAuthStoreHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISVNGnomeKeyringPasswordProvider getGnomeKeyringPasswordProvider() {
|
||||
return myISVNGnomeKeyringPasswordProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSSLPassphrasePromptSupported() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
ensureListenerCreated();
|
||||
myDelegate = new DefaultSVNPersistentAuthenticationProvider(authDir, userName, delegatingOptions, getDefaultOptions(), getHostOptionsProvider()) {
|
||||
@Override
|
||||
protected IPasswordStorage[] createPasswordStorages(DefaultSVNOptions options) {
|
||||
final IPasswordStorage[] passwordStorages = super.createPasswordStorages(options);
|
||||
final IPasswordStorage[] proxied = new IPasswordStorage[passwordStorages.length];
|
||||
for (int i = 0; i < passwordStorages.length; i++) {
|
||||
final IPasswordStorage storage = passwordStorages[i];
|
||||
proxied[i] = new ProxyPasswordStorageForDebug(storage, myListener);
|
||||
}
|
||||
return proxied;
|
||||
}
|
||||
};
|
||||
myAuthDir = authDir;
|
||||
}
|
||||
|
||||
public void setProject(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public SVNAuthentication requestClientAuthentication(final String kind, final SVNURL url, final String realm, final SVNErrorMessage errorMessage,
|
||||
final SVNAuthentication previousAuth, final boolean authMayBeStored) {
|
||||
final SVNAuthentication svnAuthentication =
|
||||
myDelegate.requestClientAuthentication(kind, url, realm, errorMessage, previousAuth, authMayBeStored);
|
||||
myListener.getMulticaster().requested(ProviderType.persistent, url, realm, kind, svnAuthentication == null);
|
||||
return svnAuthentication;
|
||||
}
|
||||
|
||||
public int acceptServerAuthentication(final SVNURL url, final String realm, final Object certificate, final boolean resultMayBeStored) {
|
||||
return ACCEPTED_TEMPORARY;
|
||||
}
|
||||
|
||||
private void actualSavePermissions(String realm, SVNAuthentication auth) {
|
||||
final String actualKind = auth.getKind();
|
||||
File dir = new File(myAuthDir, actualKind);
|
||||
String fileName = SVNFileUtil.computeChecksum(realm);
|
||||
File authFile = new File(dir, fileName);
|
||||
|
||||
try {
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, actualKind, realm);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
if (myProject != null) {
|
||||
ApplicationManager.getApplication().invokeLater(new VcsBalloonProblemNotifier(myProject,
|
||||
"<b>Problem when storing Subversion credentials:</b> " + e.getMessage(), MessageType.ERROR));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// do not make password file readonly
|
||||
setWriteable(authFile);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAuthentication(final SVNAuthentication auth, final String kind, final String realm) throws SVNException {
|
||||
final Boolean fromInteractive = ourJustEntered.get();
|
||||
ourJustEntered.set(null);
|
||||
if (! Boolean.TRUE.equals(fromInteractive)) {
|
||||
// not what user entered
|
||||
return;
|
||||
}
|
||||
|
||||
myListener.getMulticaster().saveAttemptStarted(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveAuthentication(auth, kind, realm);
|
||||
myListener.getMulticaster().saveAttemptFinished(ProviderType.persistent, auth.getURL(), realm, auth.getKind());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFingerprints(String realm, byte[] fingerprints) {
|
||||
((ISVNPersistentAuthenticationProvider) myDelegate).saveFingerprints(realm, fingerprints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] loadFingerprints(String realm) {
|
||||
return ((ISVNPersistentAuthenticationProvider) myDelegate).loadFingerprints(realm);
|
||||
}
|
||||
|
||||
private final static int maxAttempts = 10;
|
||||
private void setWriteable(final File file) {
|
||||
if (! file.exists()) return;
|
||||
if (file.getParentFile() == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < maxAttempts; i++) {
|
||||
final File parent = file.getParentFile();
|
||||
try {
|
||||
final File tempFile = FileUtil.createTempFile(parent, "123", "1", true);
|
||||
FileUtil.delete(tempFile);
|
||||
if (! file.renameTo(tempFile)) continue;
|
||||
if (! file.createNewFile()) continue;
|
||||
FileUtil.copy(tempFile, file);
|
||||
FileUtil.delete(tempFile);
|
||||
return;
|
||||
}
|
||||
catch (IOException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyHostKey(String hostName, int port, String keyAlgorithm, byte[] hostKey) throws SVNException {
|
||||
myKeyAlgorithm.put(Thread.currentThread(), keyAlgorithm);
|
||||
try {
|
||||
super.verifyHostKey(hostName, port, keyAlgorithm, hostKey);
|
||||
} finally {
|
||||
myKeyAlgorithm.remove(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSSHKeyAlgorithm() {
|
||||
return myKeyAlgorithm.get(Thread.currentThread());
|
||||
}
|
||||
|
||||
public ISVNProxyManager getProxyManager(SVNURL url) throws SVNException {
|
||||
// this code taken from default manager (changed for system properties reading)
|
||||
String host = url.getHost();
|
||||
|
||||
String proxyHost = getServersPropertyIdea(host, "http-proxy-host");
|
||||
if ((proxyHost == null) || "".equals(proxyHost.trim())) {
|
||||
if (myConfig.isIsUseDefaultProxy()) {
|
||||
// ! use common proxy if it is set
|
||||
final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
|
||||
final String ideaWideProxyHost = httpConfigurable.PROXY_HOST;
|
||||
String ideaWideProxyPort = String.valueOf(httpConfigurable.PROXY_PORT);
|
||||
|
||||
if (ideaWideProxyPort == null) {
|
||||
ideaWideProxyPort = "3128";
|
||||
}
|
||||
|
||||
if ((ideaWideProxyHost != null) && (! "".equals(ideaWideProxyHost.trim()))) {
|
||||
return new MyPromptingProxyManager(ideaWideProxyHost, ideaWideProxyPort);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
String proxyExceptions = getServersPropertyIdea(host, "http-proxy-exceptions");
|
||||
String proxyExceptionsSeparator = ",";
|
||||
if (proxyExceptions == null) {
|
||||
proxyExceptions = System.getProperty("http.nonProxyHosts");
|
||||
proxyExceptionsSeparator = "|";
|
||||
}
|
||||
if (proxyExceptions != null) {
|
||||
for(StringTokenizer exceptions = new StringTokenizer(proxyExceptions, proxyExceptionsSeparator); exceptions.hasMoreTokens();) {
|
||||
String exception = exceptions.nextToken().trim();
|
||||
if (DefaultSVNOptions.matches(exception, host)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
String proxyPort = getServersPropertyIdea(host, "http-proxy-port");
|
||||
String proxyUser = getServersPropertyIdea(host, "http-proxy-username");
|
||||
String proxyPassword = getServersPropertyIdea(host, "http-proxy-password");
|
||||
return new MySimpleProxyManager(proxyHost, proxyPort, proxyUser, proxyPassword);
|
||||
}
|
||||
|
||||
private static class MyPromptingProxyManager extends MySimpleProxyManager {
|
||||
private static final String ourPrompt = "Proxy authentication";
|
||||
|
||||
private MyPromptingProxyManager(final String host, final String port) {
|
||||
super(host, port, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProxyUserName() {
|
||||
if (myProxyUser != null) {
|
||||
return myProxyUser;
|
||||
}
|
||||
final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
|
||||
if (httpConfigurable.PROXY_AUTHENTICATION && (! httpConfigurable.KEEP_PROXY_PASSWORD)) {
|
||||
httpConfigurable.getPromptedAuthentication(myProxyHost, ourPrompt);
|
||||
}
|
||||
myProxyUser = httpConfigurable.PROXY_LOGIN;
|
||||
return myProxyUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProxyPassword() {
|
||||
if (myProxyPassword != null) {
|
||||
return myProxyPassword;
|
||||
}
|
||||
final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
|
||||
if (httpConfigurable.PROXY_AUTHENTICATION && (! httpConfigurable.KEEP_PROXY_PASSWORD)) {
|
||||
httpConfigurable.getPromptedAuthentication(myProxyUser, ourPrompt);
|
||||
}
|
||||
myProxyPassword = httpConfigurable.getPlainProxyPassword();
|
||||
return myProxyPassword;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MySimpleProxyManager implements ISVNProxyManager {
|
||||
protected String myProxyHost;
|
||||
private final String myProxyPort;
|
||||
protected String myProxyUser;
|
||||
protected String myProxyPassword;
|
||||
|
||||
public MySimpleProxyManager(String host, String port, String user, String password) {
|
||||
myProxyHost = host;
|
||||
myProxyPort = port == null ? "3128" : port;
|
||||
myProxyUser = user;
|
||||
myProxyPassword = password;
|
||||
}
|
||||
|
||||
public String getProxyHost() {
|
||||
return myProxyHost;
|
||||
}
|
||||
|
||||
public int getProxyPort() {
|
||||
try {
|
||||
return Integer.parseInt(myProxyPort);
|
||||
} catch (NumberFormatException nfe) {
|
||||
//
|
||||
}
|
||||
return 3128;
|
||||
}
|
||||
|
||||
public String getProxyUserName() {
|
||||
return myProxyUser;
|
||||
}
|
||||
|
||||
public String getProxyPassword() {
|
||||
return myProxyPassword;
|
||||
}
|
||||
|
||||
public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
// 30 seconds
|
||||
private final static int DEFAULT_READ_TIMEOUT = 30 * 1000;
|
||||
|
||||
@Override
|
||||
public int getReadTimeout(final SVNRepository repository) {
|
||||
String protocol = repository.getLocation().getProtocol();
|
||||
if (HTTP.equals(protocol) || HTTPS.equals(protocol)) {
|
||||
String host = repository.getLocation().getHost();
|
||||
String timeout = getServersPropertyIdea(host, "http-timeout");
|
||||
if (timeout != null) {
|
||||
try {
|
||||
return Integer.parseInt(timeout)*1000;
|
||||
} catch (NumberFormatException nfe) {
|
||||
// use default
|
||||
}
|
||||
}
|
||||
return DEFAULT_READ_TIMEOUT;
|
||||
}
|
||||
if (SVN_SSH.equals(protocol)) {
|
||||
return (int) myConfig.mySSHReadTimeout;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConnectTimeout(SVNRepository repository) {
|
||||
String protocol = repository.getLocation().getProtocol();
|
||||
if (SVN_SSH.equals(protocol)) {
|
||||
return (int) myConfig.mySSHConnectionTimeout;
|
||||
}
|
||||
final int connectTimeout = super.getConnectTimeout(repository);
|
||||
if ((HTTP.equals(protocol) || HTTPS.equals(protocol)) && (connectTimeout <= 0)) {
|
||||
return DEFAULT_READ_TIMEOUT;
|
||||
}
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
// taken from default manager as is
|
||||
private String getServersPropertyIdea(String host, final String name) {
|
||||
final SVNCompositeConfigFile serversFile = getHostOptionsProvider().getServersFile();
|
||||
return getPropertyIdea(host, serversFile, name);
|
||||
}
|
||||
|
||||
private String getPropertyIdea(String host, SVNCompositeConfigFile serversFile, final String name) {
|
||||
String groupName = getGroupName(serversFile.getProperties("groups"), host);
|
||||
if (groupName != null) {
|
||||
Map hostProps = serversFile.getProperties(groupName);
|
||||
final String value = (String)hostProps.get(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Map globalProps = serversFile.getProperties("global");
|
||||
return (String) globalProps.get(name);
|
||||
}
|
||||
|
||||
public static boolean checkHostGroup(final String url, final String patterns, final String exceptions) {
|
||||
final SVNURL svnurl;
|
||||
try {
|
||||
svnurl = SVNURL.parseURIEncoded(url);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String host = svnurl.getHost();
|
||||
return matches(patterns, host) && (! matches(exceptions, host));
|
||||
}
|
||||
|
||||
private static boolean matches(final String pattern, final String host) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(pattern, ",");
|
||||
while(tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (DefaultSVNOptions.matches(token, host)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// taken from default manager as is
|
||||
private static String getGroupName(Map groups, String host) {
|
||||
for (Iterator names = groups.keySet().iterator(); names.hasNext();) {
|
||||
String name = (String) names.next();
|
||||
String pattern = (String) groups.get(name);
|
||||
for(StringTokenizer tokens = new StringTokenizer(pattern, ","); tokens.hasMoreTokens();) {
|
||||
String token = tokens.nextToken();
|
||||
if (DefaultSVNOptions.matches(token, host)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// default = yes
|
||||
private static boolean isTurned(final String value) {
|
||||
return value == null || "yes".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
|
||||
}
|
||||
|
||||
private ModalityState getCurrent() {
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
return ModalityState.current();
|
||||
}
|
||||
final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (pi == null) {
|
||||
return ModalityState.defaultModalityState();
|
||||
}
|
||||
return pi.getModalityState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a yes/no question whether user wants to store his password in plain text and returns his answer.
|
||||
* @param title title of the questioning dialog.
|
||||
* @param message questioning message to be displayed.
|
||||
* @return true if user agrees to store his password in plaintext, false if he doesn't.
|
||||
*/
|
||||
@CalledInAwt
|
||||
private boolean askToStoreUnencrypted(String title, String message) {
|
||||
final int answer = Messages.showYesNoDialog(myProject, message, title, Messages.getQuestionIcon());
|
||||
return answer == 0;
|
||||
}
|
||||
|
||||
public void setInteraction(SvnAuthenticationInteraction interaction) {
|
||||
myInteraction = interaction;
|
||||
}
|
||||
|
||||
private static class MySvnAuthenticationInteraction implements SvnAuthenticationInteraction {
|
||||
private final Project myProject;
|
||||
|
||||
private MySvnAuthenticationInteraction(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warnOnAuthStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store credentials: forbidden by \"store-auth-creds=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warnOnPasswordStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store password: forbidden by \"store-passwords=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warnOnSSLPassphraseStorageDisabled(SVNURL url) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp=no\"", MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promptForPlaintextPasswordSaving(SVNURL url, String realm) {
|
||||
final int answer = Messages.showYesNoDialog(myProject, String.format("Your password for authentication realm:\n" +
|
||||
"%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?", realm),
|
||||
"Store the password in plaintext?", Messages.getQuestionIcon());
|
||||
return answer == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promptInAwt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promptForSSLPlaintextPassphraseSaving(SVNURL url, String realm, File certificateFile, String certificateName) {
|
||||
final int answer = Messages.showYesNoDialog(myProject,
|
||||
String.format("Your passphrase for " + certificateName + ":\n%s\ncan only be stored to disk unencrypted. Would you like to store it in plaintext?",
|
||||
certificateFile.getPath()),
|
||||
"Store the passphrase in plaintext?", Messages.getQuestionIcon());
|
||||
return answer == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLion() {
|
||||
return SystemInfo.isMac && SystemInfo.isMacOSSnowLeopard && ! SystemInfo.OS_VERSION.startsWith("10.6");
|
||||
}
|
||||
|
||||
public class IdeaSVNHostOptionsProvider extends DefaultSVNHostOptionsProvider {
|
||||
public IdeaSVNHostOptionsProvider() {
|
||||
super(myConfigDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SVNCompositeConfigFile getServersFile() {
|
||||
return super.getServersFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISVNHostOptions getHostOptions(SVNURL url) {
|
||||
return new IdeaSVNHostOptions(getServersFile(), url);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThreadLocalSavePermissions {
|
||||
private final Map<Thread, Boolean> myPlainTextAllowed;
|
||||
|
||||
private ThreadLocalSavePermissions() {
|
||||
myPlainTextAllowed = Collections.synchronizedMap(new HashMap<Thread, Boolean>());
|
||||
}
|
||||
|
||||
public void put(final boolean value) {
|
||||
myPlainTextAllowed.put(Thread.currentThread(), value);
|
||||
}
|
||||
|
||||
public boolean have() {
|
||||
return myPlainTextAllowed.containsKey(Thread.currentThread());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
myPlainTextAllowed.remove(Thread.currentThread());
|
||||
}
|
||||
|
||||
public boolean allowed() {
|
||||
return Boolean.TRUE.equals(myPlainTextAllowed.get(Thread.currentThread()));
|
||||
}
|
||||
}
|
||||
|
||||
private class IdeaSVNHostOptions extends DefaultSVNHostOptions {
|
||||
private SVNCompositeConfigFile myConfigFile;
|
||||
private final SVNURL myUrl;
|
||||
|
||||
private IdeaSVNHostOptions(SVNCompositeConfigFile serversFile, SVNURL url) {
|
||||
super(serversFile, url);
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStorePlainTextPasswords(final String realm, SVNAuthentication auth) throws SVNException {
|
||||
if (USERNAME.equals(auth.getKind())) return true;
|
||||
|
||||
final boolean superValue = super.isStorePlainTextPasswords(realm, auth);
|
||||
final boolean value = mySavePermissions.allowed() || superValue;
|
||||
if ((! value) && (! mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
return myInteraction.promptForPlaintextPasswordSaving(myUrl, realm);
|
||||
}
|
||||
});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStorePlainTextPassphrases(final String realm, final SVNAuthentication auth) throws SVNException {
|
||||
if (USERNAME.equals(auth.getKind())) return true;
|
||||
|
||||
final boolean value = mySavePermissions.allowed() || super.isStorePlainTextPassphrases(realm, auth);
|
||||
if ((! value) && (! mySavePermissions.have())) {
|
||||
promptAndSaveWhenWeLackEncryption(realm, auth, new Getter<Boolean>() {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
File file = null;
|
||||
String certificateName = null;
|
||||
if (auth instanceof SVNSSLAuthentication) {
|
||||
file = ((SVNSSLAuthentication) auth).getCertificateFile();
|
||||
certificateName = "client certificate";
|
||||
} else if (auth instanceof SVNSSHAuthentication) {
|
||||
file = ((SVNSSHAuthentication) auth).getPrivateKeyFile();
|
||||
certificateName = "private key file";
|
||||
} else {
|
||||
assert false;
|
||||
}
|
||||
return myInteraction.promptForSSLPlaintextPassphraseSaving(myUrl, realm,
|
||||
file, certificateName);
|
||||
}
|
||||
});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthStorageEnabled() {
|
||||
final boolean value;
|
||||
if (hasAuthStorageEnabledOption()) {
|
||||
value = super.isAuthStorageEnabled();
|
||||
} else {
|
||||
value = isTurned(getConfigFile().getPropertyValue("auth", "store-auth-creds"));
|
||||
}
|
||||
if (! value) {
|
||||
myInteraction.warnOnAuthStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStorePasswords() {
|
||||
final String storePasswords = getStorePasswords();
|
||||
final boolean value;
|
||||
if (storePasswords != null) {
|
||||
value = isTurned(storePasswords);
|
||||
} else {
|
||||
final String configValue = getConfigFile().getPropertyValue("auth", "store-passwords");
|
||||
value = isTurned(configValue);
|
||||
}
|
||||
if (! value) {
|
||||
myInteraction.warnOnPasswordStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStoreSSLClientCertificatePassphrases() {
|
||||
final boolean value = super.isStoreSSLClientCertificatePassphrases();
|
||||
if (! value) {
|
||||
myInteraction.warnOnSSLPassphraseStorageDisabled(myUrl);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getStorePasswords() {
|
||||
return getServersPropertyIdea(getHost(), "store-passwords");
|
||||
}
|
||||
|
||||
private SVNCompositeConfigFile getConfigFile() {
|
||||
if (myConfigFile == null) {
|
||||
final File config = new File(myConfigDirectory, "config");
|
||||
SVNConfigFile.createDefaultConfiguration(myConfigDirectory);
|
||||
SVNConfigFile userConfig = new SVNConfigFile(config);
|
||||
SVNConfigFile systemConfig = new SVNConfigFile(new File(SVNFileUtil.getSystemConfigurationDirectory(), "config"));
|
||||
myConfigFile = new SVNCompositeConfigFile(systemConfig, userConfig);
|
||||
}
|
||||
return myConfigFile;
|
||||
}
|
||||
|
||||
private void promptAndSaveWhenWeLackEncryption(final String realm, final SVNAuthentication auth, final Getter<Boolean> prompt) {
|
||||
final Boolean[] saveOnce = new Boolean[1];
|
||||
final Runnable actualSave = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mySavePermissions.put(Boolean.TRUE.equals(saveOnce[0]));
|
||||
try {
|
||||
myPersistentAuthenticationProviderProxy.actualSavePermissions(realm, auth);
|
||||
}
|
||||
finally {
|
||||
mySavePermissions.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (myInteraction.promptInAwt()) {
|
||||
new AbstractCalledLater(myProject, getCurrent()) {
|
||||
@Override
|
||||
public void run() {
|
||||
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
|
||||
ApplicationManager.getApplication().executeOnPooledThread(actualSave);
|
||||
}
|
||||
}.callMe();
|
||||
} else {
|
||||
saveOnce[0] = Boolean.TRUE.equals(prompt.get());
|
||||
actualSave.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProxyPasswordStorageForDebug implements DefaultSVNPersistentAuthenticationProvider.IPasswordStorage {
|
||||
private final DefaultSVNPersistentAuthenticationProvider.IPasswordStorage myDelegate;
|
||||
private final EventDispatcher<SvnAuthenticationListener> myListener;
|
||||
|
||||
public ProxyPasswordStorageForDebug(final DefaultSVNPersistentAuthenticationProvider.IPasswordStorage delegate,
|
||||
final EventDispatcher<SvnAuthenticationListener> listener) {
|
||||
myDelegate = delegate;
|
||||
myListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassType() {
|
||||
return myDelegate.getPassType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean savePassword(String realm, String password, SVNAuthentication auth, SVNProperties authParameters) throws SVNException {
|
||||
final boolean saved = myDelegate.savePassword(realm, password, auth, authParameters);
|
||||
if (saved) {
|
||||
myListener.getMulticaster().actualSaveWillBeTried(ProviderType.persistent, auth.getURL(), realm, auth.getKind()
|
||||
);
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readPassword(String realm, String userName, SVNProperties authParameters) throws SVNException {
|
||||
return myDelegate.readPassword(realm, userName, authParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean savePassphrase(String realm, String passphrase, SVNAuthentication auth, SVNProperties authParameters, boolean force)
|
||||
throws SVNException {
|
||||
final boolean saved = myDelegate.savePassphrase(realm, passphrase, auth, authParameters, force);
|
||||
if (saved) {
|
||||
myListener.getMulticaster().actualSaveWillBeTried(ProviderType.persistent, auth.getURL(), realm, auth.getKind()
|
||||
);
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readPassphrase(String realm, SVNProperties authParameters) throws SVNException {
|
||||
return myDelegate.readPassphrase(realm, authParameters);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyKeyringMasterKeyProvider implements ISVNGnomeKeyringPasswordProvider {
|
||||
private final Project myProject;
|
||||
|
||||
public MyKeyringMasterKeyProvider(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyringPassword(final String keyringName) throws SVNException {
|
||||
final String[] s = new String[1];
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
s[0] = Messages.showInputDialog(myProject, "Please provide '" + keyringName + "' GNOME Keyring password", "Subversion", Messages.getQuestionIcon());
|
||||
}
|
||||
});
|
||||
return s[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.impl.GenericNotifierImpl;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.dialogs.SvnInteractiveAuthenticationProvider;
|
||||
import org.tmatesoft.svn.core.SVNAuthenticationException;
|
||||
import org.tmatesoft.svn.core.SVNCancelException;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.auth.SVNAuthentication;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
|
||||
public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthenticationNotifier.AuthenticationRequest, SVNURL> {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAuthenticationNotifier");
|
||||
|
||||
private final SvnVcs17 myVcs;
|
||||
private final RootsToWorkingCopies myRootsToWorkingCopies;
|
||||
private final Map<SVNURL, Boolean> myCopiesPassiveResults;
|
||||
private Timer myTimer;
|
||||
private volatile boolean myVerificationInProgress;
|
||||
|
||||
public SvnAuthenticationNotifier(final SvnVcs17 svnVcs) {
|
||||
super(svnVcs.getProject(), svnVcs.getDisplayName(), "Not Logged In to Subversion", NotificationType.ERROR);
|
||||
myVcs = svnVcs;
|
||||
myRootsToWorkingCopies = myVcs.getRootsToWorkingCopies();
|
||||
myCopiesPassiveResults = Collections.synchronizedMap(new HashMap<SVNURL, Boolean>());
|
||||
myVerificationInProgress = false;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (myTimer != null) {
|
||||
stop();
|
||||
}
|
||||
myTimer = new Timer("SVN authentication timer");
|
||||
// every 10 minutes
|
||||
myTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
myCopiesPassiveResults.clear();
|
||||
}
|
||||
}, 10000, 10 * 60 * 1000);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myTimer.cancel();
|
||||
myTimer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ask(final AuthenticationRequest obj, String description) {
|
||||
if (myVerificationInProgress) {
|
||||
return showAlreadyChecking();
|
||||
}
|
||||
myVerificationInProgress = true;
|
||||
|
||||
final Ref<Boolean> resultRef = new Ref<Boolean>();
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final boolean result =
|
||||
interactiveValidation(obj.myProject, obj.getUrl(), obj.getRealm(), obj.getKind());
|
||||
log("ask result for: " + obj.getUrl() + " is: " + result);
|
||||
resultRef.set(result);
|
||||
if (result) {
|
||||
onStateChangedToSuccess(obj);
|
||||
}
|
||||
} finally {
|
||||
myVerificationInProgress = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean showAlreadyChecking() {
|
||||
final IdeFrame frameFor = WindowManagerEx.getInstanceEx().findFrameFor(myProject);
|
||||
if (frameFor != null) {
|
||||
final JComponent component = frameFor.getComponent();
|
||||
Point point = component.getMousePosition();
|
||||
if (point == null) {
|
||||
point = new Point((int)(component.getWidth() * 0.7), 0);
|
||||
}
|
||||
SwingUtilities.convertPointToScreen(point, component);
|
||||
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("Already checking...", MessageType.WARNING, null).
|
||||
createBalloon().show(new RelativePoint(point), Balloon.Position.below);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void onStateChangedToSuccess(final AuthenticationRequest obj) {
|
||||
myCopiesPassiveResults.put(getKey(obj), true);
|
||||
myVcs.invokeRefreshSvnRoots(false);
|
||||
|
||||
final List<SVNURL> outdatedRequests = new LinkedList<SVNURL>();
|
||||
final Collection<SVNURL> keys = getAllCurrentKeys();
|
||||
for (SVNURL key : keys) {
|
||||
final SVNURL commonURLAncestor = SVNURLUtil.getCommonURLAncestor(key, obj.getUrl());
|
||||
if ((commonURLAncestor != null) && (! StringUtil.isEmptyOrSpaces(commonURLAncestor.getHost())) &&
|
||||
(! StringUtil.isEmptyOrSpaces(commonURLAncestor.getPath()))) {
|
||||
//final AuthenticationRequest currObj = getObj(key);
|
||||
//if ((currObj != null) && passiveValidation(myVcs.getProject(), key, true, currObj.getRealm(), currObj.getKind())) {
|
||||
outdatedRequests.add(key);
|
||||
//}
|
||||
}
|
||||
}
|
||||
log("on state changed ");
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (SVNURL key : outdatedRequests) {
|
||||
removeLazyNotificationByKey(key);
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ensureNotify(AuthenticationRequest obj) {
|
||||
final SVNURL key = getKey(obj);
|
||||
myCopiesPassiveResults.remove(key);
|
||||
/*VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "You are not authenticated to '" + obj.getRealm() + "'." +
|
||||
"To login, see pending notifications.", MessageType.ERROR);*/
|
||||
super.ensureNotify(obj);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SVNURL getKey(final AuthenticationRequest obj) {
|
||||
// !!! wc's URL
|
||||
return obj.getWcUrl();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SVNURL getWcUrl(final AuthenticationRequest obj) {
|
||||
if (obj.isOutsideCopies()) return null;
|
||||
if (obj.getWcUrl() != null) return obj.getWcUrl();
|
||||
|
||||
final WorkingCopy copy = myRootsToWorkingCopies.getMatchingCopy(obj.getUrl());
|
||||
if (copy != null) {
|
||||
obj.setOutsideCopies(false);
|
||||
obj.setWcUrl(copy.getUrl());
|
||||
} else {
|
||||
obj.setOutsideCopies(true);
|
||||
}
|
||||
return copy == null ? null : copy.getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bases on presence of notifications!
|
||||
*/
|
||||
public ThreeState isAuthenticatedFor(final VirtualFile vf) {
|
||||
final WorkingCopy wcCopy = myRootsToWorkingCopies.getWcRoot(vf);
|
||||
if (wcCopy == null) return ThreeState.UNSURE;
|
||||
|
||||
// check there's no cancellation yet
|
||||
final boolean haveCancellation = getStateFor(wcCopy.getUrl());
|
||||
if (haveCancellation) return ThreeState.NO;
|
||||
|
||||
final Boolean keptResult = myCopiesPassiveResults.get(wcCopy.getUrl());
|
||||
if (Boolean.TRUE.equals(keptResult)) return ThreeState.YES;
|
||||
if (Boolean.FALSE.equals(keptResult)) return ThreeState.NO;
|
||||
|
||||
// check have credentials
|
||||
final boolean calculatedResult = passiveValidation(myVcs.getProject(), wcCopy.getUrl());
|
||||
myCopiesPassiveResults.put(wcCopy.getUrl(), calculatedResult);
|
||||
return calculatedResult ? ThreeState.YES : ThreeState.NO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getNotificationContent(AuthenticationRequest obj) {
|
||||
return "<a href=\"\">Click to fix.</a> Not logged In to Subversion '" + obj.getRealm() + "' (" + obj.getUrl().toDecodedString() + ")";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getToString(AuthenticationRequest obj) {
|
||||
return "Click to fix. Not logged In to Subversion '" + obj.getRealm() + "' (" + obj.getUrl().toDecodedString() + ")";
|
||||
}
|
||||
|
||||
public static class AuthenticationRequest {
|
||||
private final Project myProject;
|
||||
private final String myKind;
|
||||
private final SVNURL myUrl;
|
||||
private final String myRealm;
|
||||
|
||||
private SVNURL myWcUrl;
|
||||
private boolean myOutsideCopies;
|
||||
|
||||
public AuthenticationRequest(Project project, String kind, SVNURL url, String realm) {
|
||||
myProject = project;
|
||||
myKind = kind;
|
||||
myUrl = url;
|
||||
myRealm = realm;
|
||||
}
|
||||
|
||||
public boolean isOutsideCopies() {
|
||||
return myOutsideCopies;
|
||||
}
|
||||
|
||||
public void setOutsideCopies(boolean outsideCopies) {
|
||||
myOutsideCopies = outsideCopies;
|
||||
}
|
||||
|
||||
public SVNURL getWcUrl() {
|
||||
return myWcUrl;
|
||||
}
|
||||
|
||||
public void setWcUrl(SVNURL wcUrl) {
|
||||
myWcUrl = wcUrl;
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return myKind;
|
||||
}
|
||||
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return myRealm;
|
||||
}
|
||||
}
|
||||
|
||||
static void log(final Throwable t) {
|
||||
LOG.debug(t);
|
||||
}
|
||||
|
||||
static void log(final String s) {
|
||||
LOG.debug(s);
|
||||
}
|
||||
|
||||
public static boolean passiveValidation(final Project project, final SVNURL url) {
|
||||
final SvnConfiguration17 configuration = SvnConfiguration17.getInstance(project);
|
||||
final SvnAuthenticationManager passiveManager = configuration.getPassiveAuthenticationManager();
|
||||
return validationImpl(project, url, configuration, passiveManager, false, null, null, false);
|
||||
}
|
||||
|
||||
public static boolean interactiveValidation(final Project project, final SVNURL url, final String realm, final String kind) {
|
||||
final SvnConfiguration17 configuration = SvnConfiguration17.getInstance(project);
|
||||
final SvnAuthenticationManager passiveManager = configuration.getInteractiveManager(SvnVcs17.getInstance(project));
|
||||
return validationImpl(project, url, configuration, passiveManager, true, realm, kind, true);
|
||||
}
|
||||
|
||||
private static boolean validationImpl(final Project project, final SVNURL url,
|
||||
final SvnConfiguration17 configuration, final SvnAuthenticationManager manager,
|
||||
final boolean checkWrite,
|
||||
final String realm,
|
||||
final String kind, boolean interactive) {
|
||||
SvnInteractiveAuthenticationProvider.clearCallState();
|
||||
try {
|
||||
new SVNWCClient(manager, configuration.getOptions(project)).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD);
|
||||
} catch (SVNAuthenticationException e) {
|
||||
log(e);
|
||||
return false;
|
||||
} catch (SVNCancelException e) {
|
||||
log(e); // auth canceled
|
||||
return false;
|
||||
} catch (SVNException e) {
|
||||
if (e.getErrorMessage().getErrorCode().isAuthentication()) {
|
||||
log(e);
|
||||
return false;
|
||||
}
|
||||
LOG.info("some other exc", e);
|
||||
if (interactive) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR);
|
||||
}
|
||||
return false; /// !!!! any exception means user should be notified that authorization failed
|
||||
}
|
||||
|
||||
if (! checkWrite) {
|
||||
return true;
|
||||
}
|
||||
/*if (passive) {
|
||||
return SvnInteractiveAuthenticationProvider.wasCalled();
|
||||
}*/
|
||||
|
||||
if (SvnInteractiveAuthenticationProvider.wasCalled() && SvnInteractiveAuthenticationProvider.wasCancelled()) return false;
|
||||
if (SvnInteractiveAuthenticationProvider.wasCalled()) return true;
|
||||
|
||||
final SvnVcs17 svnVcs = SvnVcs17.getInstance(project);
|
||||
|
||||
final SvnInteractiveAuthenticationProvider provider = new SvnInteractiveAuthenticationProvider(svnVcs, manager);
|
||||
final SVNAuthentication svnAuthentication = provider.requestClientAuthentication(kind, url, realm, null, null, true);
|
||||
if (svnAuthentication != null) {
|
||||
configuration.acknowledge(kind, realm, svnAuthentication);
|
||||
try {
|
||||
configuration.getAuthenticationManager(svnVcs).acknowledgeAuthentication(true, kind, realm, null, svnAuthentication);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.BinaryContentRevision;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
class SvnBinaryContentRevision extends SvnContentRevision implements BinaryContentRevision {
|
||||
public SvnBinaryContentRevision(@NotNull SvnVcs17 vcs, @NotNull final FilePath file, final SVNRevision revision, final boolean useBaseRevision) {
|
||||
super(vcs, file, revision, useBaseRevision);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public byte[] getBinaryContent() throws VcsException {
|
||||
try {
|
||||
return getUpToDateBinaryContent();
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new VcsException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return "SvnBinaryContentRevision:" + myFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class SvnBranchConfiguration {
|
||||
private String myTrunkUrl;
|
||||
private List<String> myBranchUrls;
|
||||
private boolean myUserinfoInUrl;
|
||||
|
||||
public SvnBranchConfiguration() {
|
||||
myBranchUrls = new ArrayList<String>();
|
||||
}
|
||||
|
||||
public boolean isUserinfoInUrl() {
|
||||
return myUserinfoInUrl;
|
||||
}
|
||||
|
||||
public void setUserinfoInUrl(final boolean userinfoInUrl) {
|
||||
myUserinfoInUrl = userinfoInUrl;
|
||||
}
|
||||
|
||||
public void setBranchUrls(final List<String> branchUrls) {
|
||||
myBranchUrls = branchUrls;
|
||||
Collections.sort(myBranchUrls);
|
||||
}
|
||||
|
||||
public void setTrunkUrl(final String trunkUrl) {
|
||||
myTrunkUrl = trunkUrl;
|
||||
}
|
||||
|
||||
public String getTrunkUrl() {
|
||||
return myTrunkUrl;
|
||||
}
|
||||
|
||||
public List<String> getBranchUrls() {
|
||||
return myBranchUrls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vcs.impl.VcsInitObject;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.branchConfig.*;
|
||||
import org.jetbrains.idea.svn17.integrate.SvnBranchItem;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@State(
|
||||
name = "SvnBranchConfigurationManager17",
|
||||
storages = {
|
||||
@Storage(
|
||||
file = "$PROJECT_FILE$"
|
||||
)}
|
||||
)
|
||||
public class SvnBranchConfigurationManager17 implements PersistentStateComponent<SvnBranchConfigurationManager17.ConfigurationBean> {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager");
|
||||
private final Project myProject;
|
||||
private final ProjectLevelVcsManager myVcsManager;
|
||||
private final SvnLoadedBrachesStorage17 myStorage;
|
||||
|
||||
public SvnBranchConfigurationManager17(final Project project,
|
||||
final ProjectLevelVcsManager vcsManager,
|
||||
final SvnLoadedBrachesStorage17 storage) {
|
||||
myProject = project;
|
||||
myVcsManager = vcsManager;
|
||||
myStorage = storage;
|
||||
myBunch = new NewRootBunch(project);
|
||||
}
|
||||
|
||||
public static SvnBranchConfigurationManager17 getInstance(final Project project) {
|
||||
return PeriodicalTasksCloser.getInstance().safeGetService(project, SvnBranchConfigurationManager17.class);
|
||||
}
|
||||
|
||||
public static class ConfigurationBean {
|
||||
public Map<String, SvnBranchConfiguration> myConfigurationMap = new TreeMap<String, SvnBranchConfiguration>();
|
||||
/**
|
||||
* version of "support SVN in IDEA". for features tracking. should grow
|
||||
*/
|
||||
public Long myVersion;
|
||||
public boolean mySupportsUserInfoFilter;
|
||||
}
|
||||
|
||||
public Long getSupportValue() {
|
||||
return myConfigurationBean.myVersion;
|
||||
}
|
||||
|
||||
private ConfigurationBean myConfigurationBean = new ConfigurationBean();
|
||||
private final SvnBranchConfigManager myBunch;
|
||||
|
||||
public SvnBranchConfigurationNew get(@NotNull final VirtualFile vcsRoot) throws VcsException {
|
||||
return myBunch.getConfig(vcsRoot);
|
||||
}
|
||||
|
||||
public SvnBranchConfigManager getSvnBranchConfigManager() {
|
||||
return myBunch;
|
||||
}
|
||||
|
||||
public void setConfiguration(final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) {
|
||||
myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser),
|
||||
new BranchesPreloader(myProject, myBunch, vcsRoot));
|
||||
|
||||
SvnBranchMapperManager17.getInstance().notifyBranchesChanged(myProject, vcsRoot, configuration);
|
||||
|
||||
final MessageBus messageBus = myProject.getMessageBus();
|
||||
messageBus.syncPublisher(VcsConfigurationChangeListener.BRANCHES_CHANGED).execute(myProject, vcsRoot);
|
||||
}
|
||||
|
||||
public ConfigurationBean getState() {
|
||||
final ConfigurationBean result = new ConfigurationBean();
|
||||
result.myVersion = myConfigurationBean.myVersion;
|
||||
final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs17.getInstance(myProject));
|
||||
|
||||
for (VirtualFile root : myBunch.getMapCopy().keySet()) {
|
||||
final String key = root.getPath();
|
||||
final SvnBranchConfigurationNew configOrig = myBunch.getConfig(root);
|
||||
final SvnBranchConfiguration configuration = new SvnBranchConfiguration();
|
||||
configuration.setTrunkUrl(configOrig.getTrunkUrl());
|
||||
configuration.setUserinfoInUrl(configOrig.isUserinfoInUrl());
|
||||
configuration.setBranchUrls(configOrig.getBranchUrls());
|
||||
final HashMap<String, List<SvnBranchItem>> map = new HashMap<String, List<SvnBranchItem>>();
|
||||
final Map<String, InfoStorage<List<SvnBranchItem>>> origMap = configOrig.getBranchMap();
|
||||
for (String origKey : origMap.keySet()) {
|
||||
map.put(origKey, origMap.get(origKey).getValue());
|
||||
}
|
||||
result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration));
|
||||
}
|
||||
result.mySupportsUserInfoFilter = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class BranchesPreloader implements PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> {
|
||||
private final Project myProject;
|
||||
private final VirtualFile myRoot;
|
||||
private final SvnBranchConfigManager myBunch;
|
||||
private boolean myAll;
|
||||
|
||||
public BranchesPreloader(Project project, @NotNull final SvnBranchConfigManager bunch, VirtualFile root) {
|
||||
myBunch = bunch;
|
||||
myProject = project;
|
||||
myRoot = root;
|
||||
}
|
||||
|
||||
public void consume(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
loadImpl(prev, next);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void loadImpl(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) {
|
||||
final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<String>(prev.getBranchUrls());
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(myProject);
|
||||
if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return;
|
||||
|
||||
for (String newBranchUrl : next.getBranchUrls()) {
|
||||
// check if cancel had been put
|
||||
if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return;
|
||||
if (myAll || (! oldUrls.contains(newBranchUrl))) {
|
||||
new NewRootBunch.BranchesLoadRunnable(myProject, myBunch, newBranchUrl, InfoReliability.defaultValues, myRoot, null, true).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAll(boolean all) {
|
||||
myAll = all;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadState(final ConfigurationBean object) {
|
||||
final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs17.getInstance(myProject));
|
||||
final Map<String, SvnBranchConfiguration> map = object.myConfigurationMap;
|
||||
final Map<String, SvnBranchConfiguration> newMap = new HashMap<String, SvnBranchConfiguration>(map.size(), 1);
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
|
||||
final Set<Pair<VirtualFile, SvnBranchConfigurationNew>> whatToInit = new HashSet<Pair<VirtualFile, SvnBranchConfigurationNew>>();
|
||||
for (Map.Entry<String, SvnBranchConfiguration> entry : map.entrySet()) {
|
||||
final SvnBranchConfiguration configuration = entry.getValue();
|
||||
final VirtualFile root = lfs.refreshAndFindFileByIoFile(new File(entry.getKey()));
|
||||
if (root == null) {
|
||||
LOG.info("root not found: " + entry.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
final SvnBranchConfiguration configToConvert;
|
||||
if ((! myConfigurationBean.mySupportsUserInfoFilter) || configuration.isUserinfoInUrl()) {
|
||||
configToConvert = helper.afterDeserialization(entry.getKey(), configuration);
|
||||
} else {
|
||||
configToConvert = configuration;
|
||||
}
|
||||
final SvnBranchConfigurationNew newConfig = new SvnBranchConfigurationNew();
|
||||
newConfig.setTrunkUrl(configToConvert.getTrunkUrl());
|
||||
newConfig.setUserinfoInUrl(configToConvert.isUserinfoInUrl());
|
||||
for (String branchUrl : configToConvert.getBranchUrls()) {
|
||||
List<SvnBranchItem> stored = getStored(branchUrl);
|
||||
if (stored != null && ! stored.isEmpty()) {
|
||||
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(stored, InfoReliability.setByUser));
|
||||
} else {
|
||||
whatToInit.add(new Pair<VirtualFile, SvnBranchConfigurationNew>(root, newConfig));
|
||||
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty));
|
||||
}
|
||||
}
|
||||
|
||||
myBunch.updateForRoot(root, new InfoStorage<SvnBranchConfigurationNew>(newConfig, InfoReliability.setByUser), null);
|
||||
}
|
||||
((ProjectLevelVcsManagerImpl) myVcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : whatToInit) {
|
||||
final BranchesPreloader branchesPreloader = new BranchesPreloader(myProject, myBunch, pair.getFirst());
|
||||
branchesPreloader.setAll(true);
|
||||
branchesPreloader.loadImpl(null, pair.getSecond());
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
object.myConfigurationMap.clear();
|
||||
object.myConfigurationMap.putAll(newMap);
|
||||
myConfigurationBean = object;
|
||||
}
|
||||
|
||||
private List<SvnBranchItem> getStored(String branchUrl) {
|
||||
Collection<SvnBranchItem> collection = myStorage.get(branchUrl);
|
||||
if (collection == null) return null;
|
||||
final List<SvnBranchItem> items = new ArrayList<SvnBranchItem>(collection);
|
||||
Collections.sort(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
private static class UrlSerializationHelper {
|
||||
private final SvnVcs17 myVcs;
|
||||
|
||||
private UrlSerializationHelper(final SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
}
|
||||
|
||||
public SvnBranchConfiguration prepareForSerialization(final SvnBranchConfiguration configuration) {
|
||||
final Ref<Boolean> withUserInfo = new Ref<Boolean>();
|
||||
final String trunkUrl = serializeUrl(configuration.getTrunkUrl(), withUserInfo);
|
||||
|
||||
if (Boolean.FALSE.equals(withUserInfo.get())) {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
final List<String> branches = configuration.getBranchUrls();
|
||||
final List<String> newBranchesList = new ArrayList<String>(branches.size());
|
||||
for (String s : branches) {
|
||||
newBranchesList.add(serializeUrl(s, withUserInfo));
|
||||
}
|
||||
|
||||
final SvnBranchConfiguration result = new SvnBranchConfiguration();
|
||||
result.setTrunkUrl(trunkUrl);
|
||||
result.setBranchUrls(newBranchesList);
|
||||
result.setUserinfoInUrl(withUserInfo.isNull() ? false : withUserInfo.get());
|
||||
return result;
|
||||
}
|
||||
|
||||
public SvnBranchConfiguration afterDeserialization(final String path, final SvnBranchConfiguration configuration) {
|
||||
if (! configuration.isUserinfoInUrl()) {
|
||||
return configuration;
|
||||
}
|
||||
final String userInfo = getUserInfo(path);
|
||||
if (userInfo == null) {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
final String newTrunkUrl = deserializeUrl(configuration.getTrunkUrl(), userInfo);
|
||||
final List<String> branches = configuration.getBranchUrls();
|
||||
final List<String> newBranchesList = new ArrayList<String>(branches.size());
|
||||
for (String s : branches) {
|
||||
newBranchesList.add(deserializeUrl(s, userInfo));
|
||||
}
|
||||
|
||||
final SvnBranchConfiguration result = new SvnBranchConfiguration();
|
||||
result.setTrunkUrl(newTrunkUrl);
|
||||
result.setBranchUrls(newBranchesList);
|
||||
result.setUserinfoInUrl(userInfo != null && userInfo.length() > 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String serializeUrl(final String url, final Ref<Boolean> withUserInfo) {
|
||||
if (Boolean.FALSE.equals(withUserInfo.get())) {
|
||||
return url;
|
||||
}
|
||||
try {
|
||||
final SVNURL svnurl = SVNURL.parseURIEncoded(url);
|
||||
if (withUserInfo.isNull()) {
|
||||
final String userInfo = svnurl.getUserInfo();
|
||||
withUserInfo.set((userInfo != null) && (userInfo.length() > 0));
|
||||
}
|
||||
if (withUserInfo.get()) {
|
||||
return SVNURL.create(svnurl.getProtocol(), null, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getUserInfo(final String path) {
|
||||
final SVNURL svnurl = myVcs.getSvnFileUrlMapping().getUrlForFile(new File(path));
|
||||
return svnurl != null ? svnurl.getUserInfo() : null;
|
||||
}
|
||||
|
||||
private String deserializeUrl(final String url, final String userInfo) {
|
||||
try {
|
||||
final SVNURL svnurl = SVNURL.parseURIEncoded(url);
|
||||
return SVNURL.create(svnurl.getProtocol(), userInfo, svnurl.getHost(), svnurl.getPort(), svnurl.getURIEncodedPath(), true).toString();
|
||||
} catch (SVNException e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.messages.Topic;
|
||||
import org.jetbrains.idea.svn17.branchConfig.SvnBranchConfigurationNew;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Holds what working copies we have for URLs
|
||||
*/
|
||||
@State(
|
||||
name = "SvnBranchMapperManager17",
|
||||
storages = {
|
||||
@Storage(
|
||||
file = "$APP_CONFIG$/other.xml"
|
||||
)}
|
||||
)
|
||||
public class SvnBranchMapperManager17 implements PersistentStateComponent<SvnBranchMapperManager17.SvnBranchMapperHolder> {
|
||||
private SvnBranchMapperHolder myStateHolder;
|
||||
|
||||
public static SvnBranchMapperManager17 getInstance() {
|
||||
return ServiceManager.getService(SvnBranchMapperManager17.class);
|
||||
}
|
||||
|
||||
public SvnBranchMapperManager17() {
|
||||
myStateHolder = new SvnBranchMapperHolder();
|
||||
}
|
||||
|
||||
public SvnBranchMapperHolder getState() {
|
||||
return myStateHolder;
|
||||
}
|
||||
|
||||
public void loadState(final SvnBranchMapperHolder state) {
|
||||
myStateHolder = state;
|
||||
}
|
||||
|
||||
public void put(final String url, final String value) {
|
||||
myStateHolder.put(url, value);
|
||||
notifyWcRootsChanged(url, Collections.unmodifiableCollection(myStateHolder.get(url)));
|
||||
}
|
||||
|
||||
public void remove(final String url, final File value) {
|
||||
final Set<String> set = myStateHolder.get(url);
|
||||
if (set != null) {
|
||||
set.remove(value.getAbsolutePath());
|
||||
}
|
||||
notifyWcRootsChanged(url, Collections.unmodifiableCollection(set));
|
||||
}
|
||||
|
||||
private static void notifyWcRootsChanged(final String url, final Collection<String> roots) {
|
||||
ApplicationManager.getApplication().getMessageBus().syncPublisher(WC_ROOTS_CHANGED).rootsChanged(url, roots);
|
||||
}
|
||||
|
||||
public void notifyBranchesChanged(final Project project, final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) {
|
||||
final Map<String, String> map = configuration.getUrl2FileMappings(project, vcsRoot);
|
||||
if (map != null) {
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> get(final String key) {
|
||||
return myStateHolder.get(key);
|
||||
}
|
||||
|
||||
public static class SvnBranchMapperHolder {
|
||||
public Map<String, Set<String>> myMapping;
|
||||
|
||||
public SvnBranchMapperHolder() {
|
||||
myMapping = new HashMap<String, Set<String>>();
|
||||
}
|
||||
|
||||
public void put(final String key, final String value) {
|
||||
Set<String> files = myMapping.get(key);
|
||||
if (files == null) {
|
||||
files = new HashSet<String>();
|
||||
myMapping.put(key, files);
|
||||
}
|
||||
files.add(value);
|
||||
}
|
||||
|
||||
public Set<String> get(final String key) {
|
||||
return myMapping.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface WcRootsChangeConsumer {
|
||||
void rootsChanged(final String url, final Collection<String> roots);
|
||||
}
|
||||
|
||||
public static final Topic<WcRootsChangeConsumer> WC_ROOTS_CHANGED =
|
||||
new Topic<WcRootsChangeConsumer>("SVN_WC_ROOTS_CHANGED", WcRootsChangeConsumer.class);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class SvnBundle {
|
||||
private static Reference<ResourceBundle> ourBundle;
|
||||
|
||||
@NonNls private static final String BUNDLE = "org.jetbrains.idea.svn17.SvnBundle";
|
||||
|
||||
private SvnBundle() {
|
||||
}
|
||||
|
||||
public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
|
||||
return CommonBundle.message(getBundle(), key, params);
|
||||
}
|
||||
|
||||
public static String getString(@PropertyKey(resourceBundle = BUNDLE)String key) {
|
||||
return getBundle().getString(key);
|
||||
}
|
||||
|
||||
private static ResourceBundle getBundle() {
|
||||
ResourceBundle bundle = null;
|
||||
if (ourBundle != null) bundle = ourBundle.get();
|
||||
if (bundle == null) {
|
||||
bundle = ResourceBundle.getBundle(BUNDLE);
|
||||
ourBundle = new SoftReference<ResourceBundle>(bundle);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
#Actions&Plugin info
|
||||
group.SubversionFileGroup.text=SVN
|
||||
action.Subversion.BrowseSVNRepository.text=Bro_wse Subversion Repository...
|
||||
action.Subversion.BrowseSVNRepository.description=Browse a Subversion repository
|
||||
group.SubversionFilePopupGroup.text=_Subversion
|
||||
action.Subversion.Add.text=_Add
|
||||
action.Subversion.Add.description=Add the file to Subversion
|
||||
group.IgnoreChoicesGroup.text=Ignore
|
||||
group.RevertIgnoreChoicesGroup.text=Remove from ignore list
|
||||
action.Subversion.UndoIgnore.text=Selected file names
|
||||
action.Subversion.UndoIgnore.description=Remove file name/mask from folder ignore list
|
||||
action.Subversion.Ignore.ExactMatch.text=Selected file names
|
||||
action.Subversion.Ignore.ExactMatch.description=Adds names of all selected files into folder ignore list
|
||||
action.Subversion.Ignore.MatchExtension.text=Extension mask
|
||||
action.Subversion.Ignore.MatchExtension.description=Adds {0} mask into folder ignore list
|
||||
action.Subversion.SetProperty.text=Set Proper_ty...
|
||||
action.Subversion.SetProperty.description=Set versioned property on file or directory
|
||||
action.Subversion.Revert.text=_Revert...
|
||||
action.Subversion.Revert.description=Revert file to pristine state
|
||||
action.Subversion.Resolve.text=Re_solve Text Conflict...
|
||||
action.Subversion.Resolve.description=Resolve text conflict on file
|
||||
action.Subversion.MarkResolved.text=_Mark Resolved...
|
||||
action.Subversion.MarkResolved.description=Mark text and properties conflicts as resolved
|
||||
action.Subversion.Clenaup.text=Cl_eanup
|
||||
action.Subversion.Clenaup.description=Unlock locked directories and run all remaining incompleted operations
|
||||
action.Subversion.Copy.text=_Branch or Tag...
|
||||
action.Subversion.Copy.description=Copy selected file or directory to the new repository location
|
||||
action.Subversion.Lock.text=_Lock...
|
||||
action.Subversion.Lock.description=Lock files
|
||||
action.Subversion.Unlock.text=Unl_ock
|
||||
action.Subversion.Unlock.description=Unlock files
|
||||
action.SvnChangesBrowser.text=Bro_wse Changes...
|
||||
plugin.Subversion.description=Provides integration with Subversion version control system
|
||||
action.name.refresh=Refresh
|
||||
action.Subversion.ImportToSVNRepository.text=I_mport into Subversion...
|
||||
action.Subversion.Share.text=_Share Directory...
|
||||
action.Subversion.ShowProperties.text=Edit _Properties
|
||||
action.Subversion.ConfigureBranches.text=Configure Branches...
|
||||
action.Subversion.CompareWithBranch.text=Compare with Branch...
|
||||
action.Subversion.Relocate.text=Relocate...
|
||||
action.Subversion.Relocate.description=Relocate working copy to a different URL
|
||||
action.Subversion.CleanupProject.text=Cleanup Project
|
||||
action.Subversion.CleanupProject.description=Perform cleanup for all working copy directories in the project
|
||||
|
||||
#Copy dialog
|
||||
dialog.title.branch=Create Branch or Tag
|
||||
label.copy.from=&From:
|
||||
label.copy.to=&To:
|
||||
label.copy.from.revision=Copy from revision:
|
||||
radio.copy.working.copy=&Working copy
|
||||
radio.copy.head=&HEAD revision
|
||||
radio.copy.specific=Specific &revision:
|
||||
label.copy.comment=&Comment
|
||||
label.copy.select.location.dialog.copy.as=Copy &as:
|
||||
|
||||
#Locl dialog
|
||||
dialog.title.lock.files=Lock Files
|
||||
dialog.title.lock.file=Lock File
|
||||
label.lock.comment=&Lock comment:
|
||||
label.locl.steal.existing=&Steal existing lock
|
||||
|
||||
#SSHCredentialsDialog
|
||||
label.ssh.authentication.realm=Authentication realm: ''{0}''
|
||||
dialog.title.openssh.v2.private.key=OpenSSH v2 Private Key
|
||||
dialog.description.openssh.v2.private.key=Select private key file for SSH authentication
|
||||
checkbox.ssh.keep.for.current.session=&Save Credentials
|
||||
label.ssh.user.name=&User name:
|
||||
radio.ssh.authentication.with.password=Authentication &with password
|
||||
label.ssh.password=&Password:
|
||||
radio.ssh.authentication.private.key=Authentication with private &key
|
||||
label.ssh.key.file=Key &File:
|
||||
label.ssh.passphrase=Passph&rase:
|
||||
label.ssh.port=Port &Number:
|
||||
|
||||
label.ssl.certificate.path=Path to certificate:
|
||||
label.ssl.certificate.password=Certificate passphrase:
|
||||
checkbox.ssl.keep.for.current.session=&Save Credentials
|
||||
|
||||
progress.text.create.remote.folder=Create Remote Folder
|
||||
message.text.error=Error
|
||||
|
||||
#Repository Browser
|
||||
dialog.title.browser.copy.or.move=Copy or Move
|
||||
dialog.title.browser.delete=Delete
|
||||
dialog.title.browser.new.folder=New Folder
|
||||
label.browser.url1.delete=Delete
|
||||
label.browser.url1.create=Create
|
||||
label.browser.url1.from=From
|
||||
label.browser.to=To
|
||||
label.browser.name.copy.as=Copy &as:
|
||||
label.browser.name.name=&Name:
|
||||
checkbox.browser.move.source.to.target=&Move source to target
|
||||
label.browser.comment=&Comment:
|
||||
label.browser.select.location=&Select location in repository:
|
||||
node.text.browser.type.valid.url=Type valid URL and click 'Refresh' to select location
|
||||
dialog.title.browser.browse.repository=Browse Subversion Repository
|
||||
label.text.browser.repository.url=Repository &URL:
|
||||
button.text.new.folder=&New Folder...
|
||||
button.text.delete=&Delete...
|
||||
button.text.copy=&Copy
|
||||
button.text.paste=&Paste...
|
||||
progres.text.deleting=Deleting {0}
|
||||
progress.title.browser.delete=Delete
|
||||
progress.text.browser.creating=Creating {0}
|
||||
progress.text.browser.moving=Moving {0}
|
||||
progress.text.browser.copying=Copying {0}
|
||||
progress.text.browser.remote.destination=To {0}
|
||||
progress.title.browser.move=Move
|
||||
progress.title.browser.copy=Copy
|
||||
node.text.browser.cannot.access.repository=Cannot access repository at ''{0}''
|
||||
progress.text.browser.establishing.connection=Establishing connection to Subversion repository
|
||||
progress.title.browser.establishing.connection=Establishing Connection...
|
||||
node.text.browser.cannot.establish.connection=Cannot establish connection to ''{0}''
|
||||
|
||||
#authentication
|
||||
label.auth.authentication.realm=Authentication realm: ''{0}''
|
||||
label.auth.user.name=&User name:
|
||||
label.auth.password=&Password:
|
||||
checkbox.auth.keep.for.current.session=&Save credentials
|
||||
label.credentials.user.name.required=User name is required for ''{0}''
|
||||
label.credentials.user.name=User name:
|
||||
checkbox.credentials.save.for.future=Save for future use
|
||||
dialog.title.authentication.required=Authentication Required
|
||||
dialog.title.authentication.required.was.failed=Authentication Required (Authentication Failed)
|
||||
|
||||
#history
|
||||
progress.title.revisions.history=Revisions History
|
||||
progress.text2.collecting.history=Collecting revisions history for ''{0}''
|
||||
checkbox.changes.filter.filter.by.author=A&uthor:
|
||||
progress.text2.processing.revision=Processing revision ''{0}''
|
||||
progress.text.changes.collecting.changes=Collecting information on changes
|
||||
progress.text2.changes.establishing.connection=Establishing connection to ''{0}''
|
||||
progress.text2.revision.processed=Revision ''{0}'' processed
|
||||
|
||||
#status
|
||||
status.configurable.display.name=Status
|
||||
status.configurable.get.out.of.date.information=Check status against se&rver
|
||||
progress.text.status.analyzing.local=Analyzing status of ''{0}''
|
||||
progress.text.status.analizyng.remote=Discovering remote status of ''{0}''
|
||||
status.group.name.missing=Missing
|
||||
status.group.name.replaced=Replaced
|
||||
status.group.name.obstructed=Obstructed
|
||||
status.group.name.externals=Externals
|
||||
status.group.name.switched=Switched
|
||||
status.group.name.locked=Locked
|
||||
|
||||
#Configuration
|
||||
checkbox.configure.use.system.default.configuration.directory=&Use system default Subversion configuration directory
|
||||
label.configuration.configuration.directory=Subversion configuration &directory:
|
||||
dialog.title.select.configuration.directory=Select Configuration Directory
|
||||
dialog.description.select.configuration.directory=Select Subversion configuration directory or create new one
|
||||
button.text.clear.authentication.cache=&Clear Auth Cache
|
||||
label.text.delete.stored.credentials=Delete all stored credentials for 'http', 'svn' and 'svn+ssh' protocols
|
||||
button.text.edit.proxies=Edit Network &Options...
|
||||
label.text.edit.proxies=Edit 'servers' Subversion runtime configuration file
|
||||
dialog.title.edit.http.proxies.settings = Edit Subversion options related to the network layers
|
||||
dialog.edit.http.proxies.settings.error.same.group.names.text=Groups with identical names detected: ''{0}''
|
||||
dialog.edit.http.proxies.settings.error.ambiguous.group.patterns.text=Found repository urls that match to several groups: {0}
|
||||
dialog.edit.http.proxies.settings.error.ambiguous.group.patterns.to.text=url {0} matches to {1}\n
|
||||
dialog.edit.http.proxies.settings.tab.edit.user.file.title=User file
|
||||
dialog.edit.http.proxies.settings.tab.edit.system.file.title=System file
|
||||
dialog.edit.http.proxies.settings.port.must.be.number.error=Port must be a number (group ''{0}'')
|
||||
dialog.edit.http.proxies.settings.timeout.must.be.number.error=HTTP timeout must be a number (group ''{0}'')
|
||||
dialog.edit.http.proxies.settings.dialog.select.ssl.client.certificate.path.title=Select path to your certificate
|
||||
dialog.edit.http.proxies.settings.dialog.select.ssl.client.certificate.path.text=Select path to your certificate
|
||||
dialog.edit.http.proxies.settings.panel.proxy.title=HTTP proxy settings
|
||||
dialog.edit.http.proxies.settings.panel.ssl.title=SSL settings
|
||||
dialog.edit.http.proxies.settings.panel.repositories.title=Repositories
|
||||
dialog.edit.http.proxies.settings.patterns.text=U&RL patterns:
|
||||
dialog.edit.http.proxies.settings.exceptions.text=E&xceptions:
|
||||
dialog.edit.http.proxies.settings.server.text=&Server:
|
||||
dialog.edit.http.proxies.settings.user.text=&User:
|
||||
dialog.edit.http.proxies.settings.port.text=P&ort:
|
||||
dialog.edit.http.proxies.settings.password.text=Pass&word:
|
||||
dialog.edit.http.proxies.settings.connection.timeout.text=Connection t&imeout:
|
||||
dialog.edit.http.proxies.settings.seconds.text=seconds
|
||||
dialog.edit.http.proxies.settings.paths.to.authority.certificates.text=Comma separated &paths to CAs certificate files:
|
||||
dialog.edit.http.proxies.settings.ssl.client.certificate.file.text=SSL &client certificate file:
|
||||
dialog.edit.http.proxies.settings.client.certificate.passphrase.text=SSL client certificate passp&hrase:
|
||||
dialog.edit.http.proxies.settings.trust.default.cas.text=Trust default C&As
|
||||
dialog.edit.http.proxies.settings.test.connection.button.text=&Test connection
|
||||
dialog.edit.http.proxies.settings.test.connection.settings.will.be.stored.title=Warning
|
||||
dialog.edit.http.proxies.settings.test.connection.settings.will.be.stored.text=Settings will be saved
|
||||
dialog.edit.http.proxies.settings.test.connection.error.title=Connection test failed
|
||||
dialog.edit.http.proxies.settings.test.connection.succes.title=Connection test successful
|
||||
dialog.edit.http.proxies.settings.test.connection.succes.text=Connection test successful
|
||||
confirmation.text.delete.stored.authentication.information=You are about to delete all stored Subversion authentication information.\nWould you like to proceed with deletion?
|
||||
confirmation.title.clear.authentication.cache=Clear Authentication Cache
|
||||
|
||||
label.configure.upgrade.label=Working Copy upgrade strategy:
|
||||
radio.configure.upgrade.ask=As&k me on attempt to upgrade
|
||||
radio.configure.upgrade.none=&Never upgrade (keep Subversion 1.3)
|
||||
radio.configure.upgrade.auto=Upgrade &automatically (use Subversion 1.4)
|
||||
radio.configure.upgrade.auto.15format=Upgrade automatically (use Subversion 1.&5)
|
||||
radio.configure.upgrade.auto.16format=Upgrade automatically (use Subversion 1.&6)
|
||||
|
||||
label.configure.create.label={0} is about to create new Subversion working copy,\n\
|
||||
please, select desired working copy format:
|
||||
label.configure.create.strategy=Create working copy directory in:
|
||||
radio.configure.create.none=1.&3 format
|
||||
radio.configure.create.auto=1.&4 format
|
||||
radio.configure.create.auto.15format=1.&5 format
|
||||
radio.configure.create.auto.16format=1.&6 format
|
||||
radio.configure.create.auto.17format=1.&7 format
|
||||
|
||||
label.configure.change.label=Change working copy ''{0}'' format to:
|
||||
radio.configure.change.none=1.&3 format
|
||||
radio.configure.change.auto=1.&4 format
|
||||
radio.configure.change.auto.15format=1.&5 format
|
||||
radio.configure.change.auto.16format=1.&6 format
|
||||
radio.configure.change.auto.17format=1.&7 format
|
||||
|
||||
label.where.svn.format.settings.text=To change above setting later, visit 'File | Settings | Version Control'
|
||||
label.where.svn.format.can.be.changed.text=''Version Control | Subversion | {0}''
|
||||
dialog.upgrade.wcopy.format.title=Subversion Working Copy Format
|
||||
|
||||
label.working.copy.root.outside.text=Working copy root is outside the directory specified in Project Settings.\nThe whole working copy will be converted.
|
||||
|
||||
progress.text.loading.contents=Loading contents of ''{0}''
|
||||
progress.text2.revision.information=Revision {0}
|
||||
progress.title.loading.file.content=Loading Remote File Content
|
||||
exception.text.file.miss.svn=File ''{0}'' is readonly, but miss svn:needs-lock property
|
||||
confirmation.text.edit.file=File(s) you're are going to edit needs to be locked before editing
|
||||
|
||||
#File statuses
|
||||
file.status.external=External (svn)
|
||||
file.status.obstructed=Obstructed (svn)
|
||||
file.status.replaced=Replaced (svn)
|
||||
file.status.switched=Switched (svn)
|
||||
|
||||
#Adding
|
||||
confirmation.text.add.file=Do you want to schedule the following file for addition to Subversion?\n{0}
|
||||
confirmation.text.add.dir=Do you want to schedule the following directory for addition to Subversion?\n{0}
|
||||
confirmation.title.add.file=Schedule for Addition
|
||||
confirmation.title.add.multiple.files=Select Files to Add to Subversion
|
||||
action.name.add.files=Adding files to {0}
|
||||
|
||||
#Ignore
|
||||
action.name.ignore.files=Adding ignore file(s) mask to {0}
|
||||
action.name.undo.ignore.files=Removing file names(or mask) from ignore list from {0}
|
||||
|
||||
# Delete
|
||||
confirmation.text.delete.file=Do you want to schedule the following file for deletion from Subversion?\n{0}
|
||||
confirmation.text.delete.dir=Do you want to schedule the following directory for deletion from Subversion?\n{0}\nNOTE: The directory will be deleted from disk when the change is committed.
|
||||
confirmation.title.delete.file=Schedule for Deletion
|
||||
confirmation.title.delete.multiple.files=Select Files to Delete from Subversion
|
||||
|
||||
progress.text.discovering.location=Discovering location for ''{0}''
|
||||
|
||||
#Lock/Unlock
|
||||
progress.text.locking.files=Locking files in repository...
|
||||
progress.text2.processing.file=Processing file {0}
|
||||
progress.title.lock.files=Lock Files
|
||||
exception.text.locking.file.failed=Failed to lock file: {0}
|
||||
message.title.lock.failures=Lock Failures
|
||||
message.text.files.locked={0,choice, 0#Failed to lock files.|1#1 file locked|2#{0,number} files locked}
|
||||
progress.text.unlocking.files=Unlocking files in repository...
|
||||
progress.title.unlock.files=Unlock Files
|
||||
exception.text.failed.to.unlock.file=Failed to unlock file: {0}
|
||||
message.title.unlock.failures=Unlock Failures
|
||||
message.text.files.unlocked={0,choice, 0#Failed to unlock files.|1#1 file unlocked|2#{0,number} files unlocked}
|
||||
|
||||
|
||||
progress.text.collection.locations=Collection Subversion Repository Locations
|
||||
message.text.no.working.copies.found=No subversion working copies found in project
|
||||
message.title.no.working.copies.found=Not working copies found
|
||||
progress.text.collecting.roots.in.module=Collecting working copy roots in module ''{0}''
|
||||
dialog.title.select.location=Select Location
|
||||
border.select.location.repository.location=Repository Location
|
||||
radio.select.location.use.project=Use project location:
|
||||
radio.select.location.use.custom=Use custom location:
|
||||
exception.text.cleanupaction.batchperform.not.implemented=CleanupAction.batchPerform not implemented
|
||||
progress.text2.adding=Adding ''{0}''
|
||||
progress.text2.deleting=Deleting ''{0}''
|
||||
progress.text2.sending=Sending ''{0}''
|
||||
progress.text2.replacing=Replacing ''{0}''
|
||||
progress.text2.transmitting.delta=Transmitting delta for ''{0}''
|
||||
progress.title.copy=Subversion Copy
|
||||
status.text.comitted.revision=Committed revision {0}.
|
||||
progress.text.copy.to=Copy to ''{0}''
|
||||
message.text.no.conflicts.found=No conflicts found
|
||||
message.title.no.conflicts.found=No Conflicts
|
||||
label.select.files.and.directories.to.mark.resolved=Select files and directories to mark resolved:
|
||||
dialog.title.mark.resolved=Mark Resolved
|
||||
action.name.mark.resolved=Mark Resolved
|
||||
action.name.resolve.conflict=Resolve Conflict
|
||||
message.text.revert.no.modifications.found=No modifications to revert found
|
||||
label.select.files.and.directories.to.revert=Select files and directories to revert:
|
||||
dialog.title.revert.files=Revert Files
|
||||
action.name.revert=&Revert
|
||||
message.title.revert.no.modifications.found=No Modifications
|
||||
action.name.revert.files=Revert files
|
||||
action.name.set.property=Set Property
|
||||
action.name.show.all.paths.affected=Show all paths affected in selected transaction
|
||||
dialog.title.affected.paths=Paths Affected in Transaction ''{0}''
|
||||
progress.text.loading.log=Loading revision log...
|
||||
exception.text.cannot.load.version=Cannot load repository version {0}
|
||||
progress.text.processing.changes=Processing changes...
|
||||
message.text.cannot.load.version=Cannot load repository version {0} :{1}
|
||||
message.title.error.fetching.affected.paths=Error Fetching Affected Paths
|
||||
exception.text.cannot.annotate.directory=Annotation operation only makes sence for files
|
||||
progress.text.computing.annotation=Computing annotation for ''{0}''
|
||||
action.text.annotate=Annotate
|
||||
checkbox.chckin.keep.files.locked=&Keep files locked
|
||||
border.show.changes.dialog.subversion.group=Subversion
|
||||
progress.title.commit=Commit
|
||||
progress.text.committing.changes.below=Creating commit packets...
|
||||
status.text.committed.revision=Committed revision {0}.
|
||||
checkin.operation.name=Comm_it
|
||||
progress.text.collecting.commitables=Collecting commitables at ''{0}''
|
||||
progress.text2.fetching.external.location=Fetching external location to ''{0}''
|
||||
progress.text2.checked.out=Checked out {1} files, checking out {0}
|
||||
progress.text2.exported=Exported {1} files, exporting {0}
|
||||
progress.text2.checked.out.revision=Checked out revision {0}.
|
||||
progress.text2.exported.revision=Exported revision {0}.
|
||||
status.text.checked.out.revision=Checked out revision {0}.
|
||||
message.text.cannot.checkout=Cannot checkout from svn: {0}
|
||||
message.text.cannot.export=Cannot export from svn: {0}
|
||||
message.title.check.out=Check Out from Subversion
|
||||
message.title.export=Export from Subversion
|
||||
progress.text.checking.out=Checking out files to ''{0}''
|
||||
progress.text.export=Exporting files to ''{0}''
|
||||
dialog.text.check.out=Check Out from Repository
|
||||
label.text.checkout.repository.url=Repository &URL:
|
||||
label.text.checkout.checkout.from=Checkout From:
|
||||
label.checkout.checkout.to=Checkout &To:
|
||||
dialof.title.select.checkout.destination=Select Checkout Destination
|
||||
dialog.description.select.checkout.destination=Select directory to checkout remote directory into or create new one
|
||||
button.text.select.all=Select &All
|
||||
button.text.deselect.all=&Deselect All
|
||||
dialog.title.select.repository.location=Select Repository Location
|
||||
button.text.ssl.accept=_Accept
|
||||
button.text.ssl.reject=_Reject
|
||||
button.text.ssh.accept=_Yes
|
||||
button.text.ssh.reject=_No
|
||||
dialog.title.ssl.examine.server.crertificate=Examine Server Certificate
|
||||
dialog.title.ssh.examine.server.fingerprints=Verify Server Key Fingerprint
|
||||
label.ssl.server.provided.certificate=Server provided the following certificate:
|
||||
label.ssh.server.provided.fingerprints=The authenticity of host {0} can''t be established.
|
||||
label.ssh.server.provided.fingerprints2={0} key fingerprint is
|
||||
label.ssh.server.provided.fingerprints3=Are you sure you want to continue connecting?
|
||||
checkbox.svn.ssh.cache.fingerprint=&Add key to Subversion cache
|
||||
dialog.title.set.property=Set Property
|
||||
label.set.property.property.name=Property &name:
|
||||
radio.set.property.set.property.value=&Set property value:
|
||||
radio.set.property.delete.property=&Delete property
|
||||
checkbox.set.property.update.properties.recursively=Update properties &recursively
|
||||
exception.text.invalid.revision=Invalid revision ''{0}''
|
||||
|
||||
#update
|
||||
update.configurable.name=Update
|
||||
checkbox.update.configurable.descend.into.child.directories=&Descend into child directories
|
||||
checkbox.update.configurable.run.status=Run &status after update
|
||||
update.switch.configurable.name=Update/Switch
|
||||
radio.update.switch.configurable.update.or.switch=U&pdate or Switch
|
||||
label.update.switch.configurable.url=&URL:
|
||||
checkbox.update.switch.configurable.to.specific.revision=Update/Switch to specific &revision:
|
||||
radio.update.switch.configurable.merge=&Merge
|
||||
label.update.switch.configurable.url1=URL &1:
|
||||
label.update.switch.configurable.revision1=Re&vision:
|
||||
lable.update.switch.configurable.url2=URL &2:
|
||||
update.switch.configurable.revision2=R&evision:
|
||||
checkbox.update.switch.configurable.try.merge.without.changes=&Try merge, but make no changes
|
||||
checkbox.update.switch.configurable.descend.into.child.directories=&Descend into child directories
|
||||
checkbox.update.switch.configurable.run.status=Run &status after update
|
||||
progress.text.merging.dry.run.changes=Merging (dry run) changes into ''{0}''
|
||||
progress.text.merging.changes=Merging changes into ''{0}''
|
||||
progress.text.updating=Updating ''{0}''
|
||||
exception.text.root.was.not.properly.updated=svn: {0} was not properly updated; may be it is already removed from the repository along with its parent.
|
||||
progress.text.update.computing.post.update.status=Computing post-update status of ''{0}''
|
||||
message.text.update.no.directories.found=No versioned directories to update was found
|
||||
messate.text.update.error=SVN: Update Error
|
||||
|
||||
progress.text2.added=Added {0}
|
||||
progress.text2.deleted=Deleted {0}
|
||||
progress.text2.conflicted=Conflicted {0}
|
||||
progress.text2.treeconflicted=Conflicted {0} (tree conflict)
|
||||
progres.text2.merged=Merged {0}
|
||||
progres.text2.updated=Updated {0}
|
||||
progress.text2.restored.file=Restored {0}
|
||||
progres.text2.updated.to.revision=Updated to revision {0}.
|
||||
status.text.updated.to.revision=Updated to revision {0}.
|
||||
progress.text2.skipped.file=Skipped {0}
|
||||
update.group.name.skipped=Skipped
|
||||
progress.text.updating.external.location=Updating external location at ''{0}''
|
||||
exception.text.update.operation.cancelled=Operation cancelled
|
||||
server.ssl.accept.temporary.action.name=Accept _Temporary
|
||||
changes.browser.change.column.name=Change
|
||||
changes.browser.author.column.name=Author
|
||||
changes.browser.date.column.name=Date
|
||||
cannot.mark.file.as.resolved.error.message=Cannot mark file as resolved: {0}
|
||||
mark.resolved.dialog.title=Mark Resolved
|
||||
mark.resolved.action.description=Mark resolved
|
||||
commit.dialog.setings.show.unresolved.checkbox=Show &unresolved
|
||||
unresolved.difference.type.name=Unresolved
|
||||
integrate.display.name=Integrate
|
||||
invalid.svn.revision.error.message=Invalid svn revision: {0}
|
||||
nulty.roots.update.configuration.affected.roots.label=Affected roots:
|
||||
nulty.roots.update.configuration.selected.root.setting.group.title=Selected Root Setting:
|
||||
integrate.configuration.revision1.label=re&vision
|
||||
integrate.configuration.source2.label=Source 2:
|
||||
integrate.configuration.revision2.label=&revision
|
||||
integrate.configuration.source1.label=Source 1:
|
||||
integrate.configuration.description.label=Integrate differences between sources into working copy (compare Source 2 to Source 1)
|
||||
source.url.could.not.be.empty.error.message=Source url could not be empty
|
||||
no.differences.between.sources.error.message=There are no differences between source and the same source
|
||||
configure.revision.specified.radio=Specified
|
||||
configure.revision.head.radio=HEAD
|
||||
update.configuration.specific.url=Update/Switch to specific &url:
|
||||
progress.text.import=Importing {0}
|
||||
message.text.cannot.import=Cannot import to svn: {0}
|
||||
message.title.import=Import to Subversion
|
||||
revision.title=Revision
|
||||
checkout.dialog.title=Checkout from Subversion
|
||||
checkout.dialog.button=Checkout
|
||||
checkout.directory.chooser.title=Checkout Directory
|
||||
checkout.directory.chooser.prompt=Select directory to checkout from Subversion
|
||||
checkout.options.dialog.title=SVN Checkout Options
|
||||
checkout.options.checkout.label=Checkout:
|
||||
checkout.options.destination.label=Destination:
|
||||
checkout.options.recursive.label=Checkout directories recursively
|
||||
checkout.options.externals.label=Include externals locations
|
||||
configure.branches.title=Configure Subversion Branches
|
||||
configure.branches.error.no.connection.title=Repository root was not found
|
||||
configure.branches.error.wrong.url=Trunk location must be under repository root
|
||||
configure.branches.trunk.location=Trunk location:
|
||||
configure.branches.branch.locations=Branch locations:
|
||||
configure.branches.item=Configure Branches...
|
||||
refresh.branches.item=Refresh Branches...
|
||||
copy.column.title=Copy
|
||||
copy.column.tooltip=Copied from {0}
|
||||
compare.with.branch.progress.loading.branches=Loading Branches
|
||||
compare.with.branch.progress.loading.content=Loading Content
|
||||
compare.with.branch.diff.title=Compare with Branch
|
||||
compare.with.branch.error.title=Compare with Branch
|
||||
compare.with.branch.popup.title=Compare with Branch
|
||||
getting.branch.configuration.error=Error retrieving branch configuration: {0}
|
||||
compare.with.branch.location.error=Couldn''t find repository location for file ''{0}'' under branch ''{1}''\nPlease check your branch configuration.
|
||||
compare.with.branch.list.error=Error Loading Branches
|
||||
create.branch.invalid.revision.error=Invalid revision ''{0}''
|
||||
create.branch.no.working.copy.error=No working copy found at {0}
|
||||
create.branch.no.base.location.error=No branch base location selected
|
||||
import.dialog.title=Import into Subversion
|
||||
import.dialog.button=Import
|
||||
repository.browser.add.location.action=Add Repository Location
|
||||
repository.browser.add.location.prompt=Repository URL:
|
||||
repository.browser.add.location.title=New Repository Location
|
||||
repository.browser.details.action=Show/Hide Details
|
||||
repository.browser.refresh.action=Refresh selected tree node
|
||||
repository.browser.add.location.menu.item=_Repository Location...
|
||||
repository.browser.edit.location.menu.item= Edit Location _Url...
|
||||
repository.browser.discard.location.action=Discard _Location
|
||||
repository.browser.discard.location.prompt=Would you like to discard the location ''{0}''?
|
||||
repository.browser.discard.location.title=Discard Location
|
||||
repository.browser.new.folder.action=Remote _Folder...
|
||||
repository.browser.history.action=Show History
|
||||
repository.browser.import.action=_Import...
|
||||
diff.options.title=Compare With Branch or Tag
|
||||
diff.options.no.url.error=Please select an URL to compare with
|
||||
diff.options.same.url.error=Please select different URLs to compare
|
||||
diff.options.no.patch.file.error=Please specify the path to save the patch file
|
||||
repository.browser.browse.changes.action=_Browse Changes...
|
||||
repository.browser.browse.changes.description=View history of changes in the selected node
|
||||
repository.browser.compare.title=Compare of ''{0} and ''{1}''
|
||||
repository.browser.compare.no.difference.message=No textual difference found between ''{0} and ''{1}''
|
||||
repository.browser.compare.no.difference.title=No Difference Found
|
||||
cleanup.action.name=Cleanup
|
||||
changes.browser.revision.term=Revision
|
||||
progress.computing.difference=Computing Difference
|
||||
progress.searching.for.files.with.conflicts=Searching for files with conflicts
|
||||
add.files.errors.title=Errors Adding Files
|
||||
move.files.errors.title=Errors Moving Files
|
||||
remove.ignore.patterns.errors.title=Errors Removing 'svn:ignore' patterns
|
||||
gather.ignore.patterns.info.progress.title=Gathering not used 'svn:ignore' patterns
|
||||
delete.files.errors.title=Errors Deleting Files
|
||||
copy.dialog.title=Branch or Tag
|
||||
move.dialog.title=Move or Rename
|
||||
select.location.invalid.url.message=Invalid Subversion repository URL: ''{0}''
|
||||
share.directory.action=Share Directory...
|
||||
share.directory.commit.message=Directory ''{0}'' created by {1}
|
||||
share.directory.title=Share Directory
|
||||
share.directory.info.message=To complete share operation commit ''{0}''.
|
||||
share.directory.create.dir.progress.text=Creating remote folder {0}
|
||||
share.directory.checkout.back.progress.text=Checking out {0}
|
||||
share.or.import.add.progress.text=Scheduling {0} for addition
|
||||
action.share.whole.project.text=Share Project (Subversion)...
|
||||
action.Subversion.integrate.changes.open.in.changelist.text=Open in changelist:
|
||||
action.Subversion.integrate.changes.select.working.copy.text=Integrate into working copy:
|
||||
action.Subversion.integrate.changes.dialog.title=Integrate To Branch
|
||||
action.Subversion.integrate.changes.message.not.under.control.text=Selected destination is not under Subversion control. Continue anyway?
|
||||
action.Subversion.integrate.changes.message.another.wc.text=Selected destination is inside working copy of another repository. Continue anyway?
|
||||
action.Subversion.integrate.changes.branch.info.source.label.text=Source branch URL: {0}
|
||||
action.Subversion.integrate.changes.branch.info.target.label.text=Target branch URL: {0}
|
||||
action.Subversion.integrate.changes.actionname=Integrate To Branch...
|
||||
action.Subversion.integrate.changes.description=Integrates selected changelist(s)/changeset into selected branch
|
||||
action.Subversion.integrate.changes.messages.title=Integrate To Branch
|
||||
action.Subversion.integrate.changes.error.no.available.files.text=No files available for integration
|
||||
action.Subversion.integrate.changes.warning.failed.list.text=Changelist {0} ({1}) integration faced problems
|
||||
action.Subversion.integrate.changes.warning.skipped.lists.text=Skipped change lists: {0}
|
||||
action.Subversion.integrate.changes.select.branch.text=Select branch to integrate to...
|
||||
action.Subversion.integrate.changes.error.source.and.target.same.text=Can not start integration: Target and source branches are the same.
|
||||
action.Subversion.integrate.changes.error.target.not.dir.text=Can not start integration: target directory does not exist or is not a directory.
|
||||
action.Subversion.integrate.changes.error.not.versioned.text=Can not start integration: target directory is not under Subversion control or does not belong to the selected branch.
|
||||
action.Subversion.integrate.changes.alien.commit.changelist.title=Integrated
|
||||
action.Subversion.integrate.changes.dialog.add.wc.text=Add
|
||||
action.Subversion.integrate.changes.dialog.remove.wc.text=Remove
|
||||
action.Subversion.integrate.changes.message.files.up.to.date.text=All files are up to date
|
||||
action.Subversion.integrate.changes.error.unable.to.collect.changes.text=Error while collecting changes to commit: {0}
|
||||
error.cannot.load.revisions=Can not load revision list
|
||||
action.Subversion.integrate.changes.message.canceled.text=Integration was canceled
|
||||
action.Subversion.integrate.changes.progress.integrating.text=Merging changes
|
||||
action.Subversion.integrate.changes.progress.integrating.details.text=Merging changelist {0}
|
||||
update.switch.to.branch.text=Use branch:
|
||||
select.branch.popup.general.title=Select branch
|
||||
progress.live.provider.loading.revisions.text=Loading revisions from server
|
||||
progress.live.provider.loading.revisions.details.text=Loading revisions from server...
|
||||
action.show.svn.map.text=Show Working Copies...
|
||||
action.show.svn.map.text.reference=Show Working Copies
|
||||
action.show.svn.map.description=Shows working copies information: working copy formats and URLs
|
||||
dialog.show.svn.map.title=Subversion Working Copies Information
|
||||
dialog.show.svn.map.label.table.header=Detected working copies
|
||||
dialog.show.svn.map.change.format.button.text=&Change Working Copy Format
|
||||
dialog.show.svn.map.table.header.column.wcpath.title=Root path
|
||||
dialog.show.svn.map.table.header.column.wcurl.title=URL
|
||||
dialog.show.svn.map.table.header.column.wcroot.title=Working copy root
|
||||
dialog.show.svn.map.table.header.column.format.title=Format
|
||||
dialog.show.svn.map.table.version13.text=1.3
|
||||
dialog.show.svn.map.table.version14.text=1.4
|
||||
dialog.show.svn.map.table.version15.text=1.5
|
||||
dialog.show.svn.map.table.version16.text=1.6
|
||||
dialog.show.svn.map.table.version17.text=1.7
|
||||
action.change.wcopy.format.task.title=Convert working copy format
|
||||
action.change.wcopy.format.task.progress.text=Converting working copy at {0} format from {1} to {2}
|
||||
action.change.wcopy.format.after.change.settings=Selected working copy format ({0}) is older than upgrade mode selected in Project Settings ({1}).\
|
||||
\nChange Project Settings upgrade mode to {0}?
|
||||
committed.changes.action.enable.merge.highlighting=Highlight integrated
|
||||
committed.changes.action.enable.merge.highlighting.description.text=Option is available for SVN repositories and working copies with 1.5 version only
|
||||
committed.changes.action.merge.highlighting.select.root=from:
|
||||
committed.changes.action.merge.highlighting.select.branch=to:
|
||||
committed.changes.action.merge.highlighting.refresh.text=Refresh
|
||||
committed.changes.action.merge.highlighting.refresh.description=Refresh merged revisions info
|
||||
committed.changes.merge.status.refreshing.text=?
|
||||
committed.changes.merge.status.integrated.text=+
|
||||
committed.changes.merge.status.not.integrated.text=-
|
||||
committed.changes.action.merge.highlighting.select.wcopy=working copy:
|
||||
dialog.Subversion.select.working.copy.title=Configure working copy paths
|
||||
dialog.Subversion.select.working.copy.wcopy.list.title=Known working copies
|
||||
upgrade.format.to15.question.title=Upgrade working copies format
|
||||
upgrade.format.to15.question.text=Do you want to upgrade Subversion working copies format to 1.5?\n\
|
||||
Note: Working copy formats can be changed through {0}
|
||||
upgrade.format.clarify.for.outside.copies.text=Working copy root ''{0}'' is outside the directory specified in Project Settings.\nConvert anyway?
|
||||
upgrade.format.to16.question.title=Upgrade Subversion working copies format
|
||||
upgrade.format.to16.question.text=Do you want to upgrade Subversion working copies format to 1.6?\n\
|
||||
Note: Working copy formats can be changed through {0}
|
||||
action.Subversion.cleanup.progress.title=Subversion cleanup
|
||||
action.Subversion.cleanup.progress.text=Performing ''{0}'' cleanup...
|
||||
action.Subversion.cleanup.project.title=Cleanup Project
|
||||
action.Subversion.cleanup.error.message=Error performing cleanup for ''{0}'': {1}
|
||||
action.working.copies.map.correct.roots.button.text=Correct &Roots
|
||||
action.working.copies.map.correct.warning.text=Some folders marked in 'Project Settings | Version Control' as under Subversion control,\n\
|
||||
are unversioned (Versioned folders may be under them).\n\
|
||||
You can use 'Correct Roots' button to perform auto correction.
|
||||
action.Subversion.properties.diff.with.local.name=Properties Diff with Local
|
||||
action.Subversion.properties.diff.name=Properties Diff
|
||||
action.Subversion.properties.difference.diff.title=Subversion properties difference: {0}
|
||||
action.Subversion.properties.difference.diff.for.move.title=Subversion properties difference: {0} -> {1}
|
||||
message.Subversion.files.can.not.be.added.to.subversion.are.not.under.working.copy.text=File(s) {0} can not be added to Subversion control since they are not under working copy.
|
||||
action.Subversion.integrate.difference.option.use.ancestry.text=&Use ancestry
|
||||
fatal.Subversion.javasvn.jar.library.version.test=javasvn.jar library is old;\nPlease make sure installation was made properly.
|
||||
subversion.problem.text=Subversion problem
|
||||
use.idea.proxy.as.default=Use {0} general proxy settings as default for Subversion
|
||||
use.idea.proxy.as.default.label.text=Use proxy settings from Settings | Plugins | HTTP Proxy Settings as default
|
||||
action.Subversion.update.use.locks.on.demand.text.configurable=Updat&e administrative information only in changed subtrees
|
||||
action.Subversion.update.use.locks.on.demand.text=Update administrative information only in &changed subtrees
|
||||
action.Subversion.update.use.locks.on.demand.description=When enabled, update only locks those parts of working copy that is about to be updated.\n\
|
||||
As a result administrative information will only be updated for working copy subtrees that has been modified during update.\n\
|
||||
Enabling this option may improve update operation performance.\n\
|
||||
Note that under some circumstances, you might have to perform "normal" update.
|
||||
switch.target.not.copy.current=Switch target URL is not a copy of current.\n Do you want to continue?
|
||||
switch.target.problem.title=Switch target problem
|
||||
tab.repository.merge.panel.title=Subversion
|
||||
tab.repository.merge.panel.root.panel.to=To:
|
||||
tab.repository.merge.panel.root.panel.from=From:
|
||||
tab.repository.merge.panel.root.panel.branch=Branch:
|
||||
tab.repository.merge.panel.root.panel.url=Url:
|
||||
tab.repository.merge.panel.root.panel.local=Local Path:
|
||||
tab.repository.merge.panel.root.panel.select.local=Please select path
|
||||
tab.repository.merge.panel.filter.plus=Filter out integrated
|
||||
tab.repository.merge.panel.filter.minus=Filter out not integrated
|
||||
tab.repository.merge.panel.filter.others=Filter out others
|
||||
browse.changes.settings.stop.on.copy=&Stop On Copy
|
||||
action.mark.list.as.merged.text=Mark As Merged
|
||||
action.mark.list.as.merged.description=Mark selected revision as merged, but do not actually merge
|
||||
action.mark.list.as.not.merged.title=Mark As Not Merged
|
||||
action.mark.list.as.not.merged.descrition=Mark selected revision as not merged, but do not change anything besides svn:mergeinfo
|
||||
label.depth.text=&Depth:
|
||||
label.depth.description=Replaces old "recursive" option. "Recursive"=false is equivalent to "immediates", "recursive"=true is equivalent to "infinity"
|
||||
undo.integrate.to.branch=Undo Integrate To Branch...
|
||||
undo.integrate.to.branch.description=Removes changes done in revision from branch
|
||||
undo.integrate.to.branch.dialog.title=Undo Integrate To Branch
|
||||
merge.source.details.title=Merge source details for {0} [{1}]
|
||||
repository.browser.edit.location.dialog.title= Edit Location Url
|
||||
loading.default.branches.configuration.text=Loading default branches configuration...
|
||||
loading.data.for.root.text=Loading data for {0}
|
||||
action.PropertiesDiff.text=Compare Subversion Properties
|
||||
action.AlienPropertiesLocalDiff.text=Compare Subversion Properties with Branch
|
||||
action.IntegrateChangeSetAction.text=Integrate to Branch
|
||||
dialog.map.working.copies.button.refresh.text=Re&fresh
|
||||
refreshing.working.copies.roots.progress.text=Refreshing working copies roots...
|
||||
retrieving.subversion.status.text=Retrieving Subversion status...
|
||||
fetching.properties.contents.progress.title=Fetching properties contents...
|
||||
show.properties.diff.progress.text.revision.information=Revision {0}
|
||||
show.properties.diff.progress.text2.property.information=Property {0}
|
||||
svn.checkout.destination.directory.title=Destination directory
|
||||
svn.checkout.destination.directory.description=Select checkout destination directory
|
||||
checkbox.ignore.whitespace.when.merge.text=&Ignore whitespaces
|
||||
svn.dialog.select.ignore.patterns.to.remove.title=Select svn:ignore patterns to remove
|
||||
svn.dialog.select.ignore.patterns.to.remove.prompt=Files being deleted are ignored by Subversion.\n\
|
||||
Some of 'svn:ignore' patterns may become outdated.\n\
|
||||
Select 'svn:ignore' patterns to be deleted.
|
||||
detect.nested.working.copies=Detect nested working copies
|
||||
svn.changeview.item.in.conflict.text=File has {0} conflict(s) and can not be committed
|
||||
svn.changeview.locally.deleted.item.in.conflict.text=File has {0} conflict(s)
|
||||
action.mark.tree.conflict.resolved.text=Mark Tree Conflict Resolved...
|
||||
action.mark.tree.conflict.resolved.confirmation.text=Do you want to mark tree conflict as resolved?
|
||||
action.mark.tree.conflict.resolved.confirmation.title=Mark Tree Conflict Resolved
|
||||
svn.integrate.changelist.warning.unresolved.conflicts.text=Integration interrupted. There are unresolved conflicts or skipped items.
|
||||
svn.option.ignore.whitespace.in.annotate=Ignore whitespace differences in annotations
|
||||
annotation.show.merge.sources.default.text=Show merge source in annotations
|
||||
svn.cannot.save.credentials.store-auth-creds=Cannot store credentials: forbidden by "store-auth-creds = no"
|
||||
annotation.original.revision=Original revision
|
||||
svn17.plugin.not.ready=<html><body>This plugin provides only basic support for Subversion 1.7.<br/>\
|
||||
Many operations are not implemented.<br/>\
|
||||
Subversion 1.7 integration is not ready yet.<br/>\
|
||||
We do NOT guarantee data safety and consistency.<br/><br/>Also, we do NOT guarantee that plugin correctly works with Subversion 1.6 and lower working copies!</body></html>
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.actions.VcsContextFactory;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.EventDispatcher;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.actions.CleanupWorker;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNNodeKind;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
*/
|
||||
public class SvnChangeProvider implements ChangeProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnChangeProvider");
|
||||
public static final String ourDefaultListName = VcsBundle.message("changes.default.changlist.name");
|
||||
|
||||
private final SvnVcs17 myVcs;
|
||||
private final VcsContextFactory myFactory;
|
||||
private final SvnFileUrlMappingImpl17 mySvnFileUrlMapping;
|
||||
|
||||
public SvnChangeProvider(final SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
myFactory = VcsContextFactory.SERVICE.getInstance();
|
||||
mySvnFileUrlMapping = (SvnFileUrlMappingImpl17) vcs.getSvnFileUrlMapping();
|
||||
}
|
||||
|
||||
public void getChanges(final VcsDirtyScope dirtyScope, final ChangelistBuilder builder, ProgressIndicator progress,
|
||||
final ChangeListManagerGate addGate) throws VcsException {
|
||||
final SvnScopeZipper zipper = new SvnScopeZipper(dirtyScope);
|
||||
zipper.run();
|
||||
|
||||
final Map<String, SvnScopeZipper.MyDirNonRecursive> nonRecursiveMap = zipper.getNonRecursiveDirs();
|
||||
final ISVNStatusFileProvider fileProvider = createFileProvider(nonRecursiveMap);
|
||||
|
||||
try {
|
||||
final SvnChangeProviderContext context = new SvnChangeProviderContext(myVcs, builder, progress);
|
||||
|
||||
final StatusWalkerPartnerImpl partner = new StatusWalkerPartnerImpl(myVcs, progress);
|
||||
final NestedCopiesBuilder nestedCopiesBuilder = new NestedCopiesBuilder();
|
||||
|
||||
final EventDispatcher<StatusReceiver> statusReceiver = EventDispatcher.create(StatusReceiver.class);
|
||||
statusReceiver.addListener(context);
|
||||
statusReceiver.addListener(nestedCopiesBuilder);
|
||||
|
||||
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(statusReceiver.getMulticaster(), partner);
|
||||
|
||||
for (FilePath path : zipper.getRecursiveDirs()) {
|
||||
walker.go(path, SVNDepth.INFINITY);
|
||||
}
|
||||
|
||||
partner.setFileProvider(fileProvider);
|
||||
for (SvnScopeZipper.MyDirNonRecursive item : nonRecursiveMap.values()) {
|
||||
walker.go(item.getDir(), SVNDepth.FILES);
|
||||
}
|
||||
|
||||
// they are taken under non recursive: ENTRIES file is read anyway, so we get to know parent status also for free
|
||||
/*for (FilePath path : zipper.getSingleFiles()) {
|
||||
FileStatus status = getParentStatus(context, path);
|
||||
processFile(path, context, status, false, context.getClient());
|
||||
}*/
|
||||
|
||||
processCopiedAndDeleted(context);
|
||||
processUnsaved(dirtyScope, addGate, context);
|
||||
|
||||
mySvnFileUrlMapping.acceptNestedData(nestedCopiesBuilder.getSet());
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processUnsaved(VcsDirtyScope dirtyScope, ChangeListManagerGate addGate, SvnChangeProviderContext context)
|
||||
throws SVNException {
|
||||
final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
|
||||
final Document[] unsavedDocuments = fileDocumentManager.getUnsavedDocuments();
|
||||
for (Document unsavedDocument : unsavedDocuments) {
|
||||
final VirtualFile file = fileDocumentManager.getFile(unsavedDocument);
|
||||
if (file != null && dirtyScope.belongsTo(new FilePathImpl(file)) && fileDocumentManager.isFileModified(file)) {
|
||||
final FileStatus status = addGate.getStatus(file);
|
||||
if (status == null || FileStatus.NOT_CHANGED.equals(status)) {
|
||||
context.addModifiedNotSavedChange(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ISVNStatusFileProvider createFileProvider(Map<String, SvnScopeZipper.MyDirNonRecursive> nonRecursiveMap) {
|
||||
// translate into terms of File.getAbsolutePath()
|
||||
final Map<String, Map> preparedMap = new HashMap<String, Map>();
|
||||
for (SvnScopeZipper.MyDirNonRecursive item : nonRecursiveMap.values()) {
|
||||
final Map result = new HashMap();
|
||||
for (FilePath path : item.getChildrenList()) {
|
||||
result.put(path.getName(), path.getIOFile());
|
||||
}
|
||||
preparedMap.put(item.getDir().getIOFile().getAbsolutePath(), result);
|
||||
}
|
||||
return new ISVNStatusFileProvider() {
|
||||
public Map getChildrenFiles(File parent) {
|
||||
return preparedMap.get(parent.getAbsolutePath());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void processCopiedAndDeleted(final SvnChangeProviderContext context) throws SVNException {
|
||||
for(SvnChangedFile copiedFile: context.getCopiedFiles()) {
|
||||
if (context.isCanceled()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
processCopiedFile(copiedFile, context.getBuilder(), context);
|
||||
}
|
||||
for(SvnChangedFile deletedFile: context.getDeletedFiles()) {
|
||||
if (context.isCanceled()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
context.processStatus(deletedFile.getFilePath(), deletedFile.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
public void getChanges(final FilePath path, final boolean recursive, final ChangelistBuilder builder) throws SVNException {
|
||||
final SvnChangeProviderContext context = new SvnChangeProviderContext(myVcs, builder, null);
|
||||
final StatusWalkerPartnerImpl partner = new StatusWalkerPartnerImpl(myVcs, ProgressManager.getInstance().getProgressIndicator());
|
||||
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(context, partner);
|
||||
walker.go(path, recursive ? SVNDepth.INFINITY : SVNDepth.IMMEDIATES);
|
||||
processCopiedAndDeleted(context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String changeListNameFromStatus(final SVNStatus status) {
|
||||
if (WorkingCopyFormat.getInstance(status.getWorkingCopyFormat()).supportsChangelists()) {
|
||||
if (SVNNodeKind.FILE.equals(status.getKind())) {
|
||||
final String clName = status.getChangelistName();
|
||||
return (clName == null) ? null : clName;
|
||||
}
|
||||
}
|
||||
// always null for earlier versions
|
||||
return null;
|
||||
}
|
||||
|
||||
private void processCopiedFile(SvnChangedFile copiedFile, ChangelistBuilder builder, SvnChangeProviderContext context) throws SVNException {
|
||||
boolean foundRename = false;
|
||||
final SVNStatus copiedStatus = copiedFile.getStatus();
|
||||
final String copyFromURL = copiedFile.getCopyFromURL();
|
||||
final FilePath copiedToPath = copiedFile.getFilePath();
|
||||
|
||||
// if copy target is _deleted_, treat like deleted, not moved!
|
||||
/*for (Iterator<SvnChangedFile> iterator = context.getDeletedFiles().iterator(); iterator.hasNext();) {
|
||||
final SvnChangedFile deletedFile = iterator.next();
|
||||
final FilePath deletedPath = deletedFile.getFilePath();
|
||||
|
||||
if (Comparing.equal(deletedPath, copiedToPath)) {
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
final Set<SvnChangedFile> deletedToDelete = new HashSet<SvnChangedFile>();
|
||||
|
||||
for (Iterator<SvnChangedFile> iterator = context.getDeletedFiles().iterator(); iterator.hasNext();) {
|
||||
SvnChangedFile deletedFile = iterator.next();
|
||||
final SVNStatus deletedStatus = deletedFile.getStatus();
|
||||
if ((deletedStatus != null) && (deletedStatus.getURL() != null) && Comparing.equal(copyFromURL, deletedStatus.getURL().toString())) {
|
||||
final String clName = changeListNameFromStatus(copiedFile.getStatus());
|
||||
builder.processChangeInList(context.createMovedChange(createBeforeRevision(deletedFile, true),
|
||||
CurrentContentRevision.create(copiedFile.getFilePath()), copiedStatus, deletedStatus), clName, SvnVcs17
|
||||
.getKey());
|
||||
deletedToDelete.add(deletedFile);
|
||||
for(Iterator<SvnChangedFile> iterChild = context.getDeletedFiles().iterator(); iterChild.hasNext();) {
|
||||
SvnChangedFile deletedChild = iterChild.next();
|
||||
final SVNStatus childStatus = deletedChild.getStatus();
|
||||
if (childStatus == null) {
|
||||
continue;
|
||||
}
|
||||
final SVNURL childUrl = childStatus.getURL();
|
||||
if (childUrl == null) {
|
||||
continue;
|
||||
}
|
||||
final String childURL = childUrl.toString();
|
||||
if (StringUtil.startsWithConcatenationOf(childURL, copyFromURL, "/")) {
|
||||
String relativePath = childURL.substring(copyFromURL.length());
|
||||
File newPath = new File(copiedFile.getFilePath().getIOFile(), relativePath);
|
||||
FilePath newFilePath = myFactory.createFilePathOn(newPath);
|
||||
if (!context.isDeleted(newFilePath)) {
|
||||
builder.processChangeInList(context.createMovedChange(createBeforeRevision(deletedChild, true),
|
||||
CurrentContentRevision.create(newFilePath),
|
||||
context.getTreeConflictStatus(newPath), childStatus), clName, SvnVcs17.getKey());
|
||||
deletedToDelete.add(deletedChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
foundRename = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final List<SvnChangedFile> deletedFiles = context.getDeletedFiles();
|
||||
for (SvnChangedFile file : deletedToDelete) {
|
||||
deletedFiles.remove(file);
|
||||
}
|
||||
|
||||
// handle the case when the deleted file wasn't included in the dirty scope - try searching for the local copy
|
||||
// by building a relative url
|
||||
if (!foundRename && copiedStatus.getURL() != null) {
|
||||
File wcPath = guessWorkingCopyPath(copiedStatus.getFile(), copiedStatus.getURL(), copyFromURL);
|
||||
SVNStatus status;
|
||||
try {
|
||||
status = context.getClient().doStatus(wcPath, false);
|
||||
}
|
||||
catch(SVNException ex) {
|
||||
status = null;
|
||||
}
|
||||
if (status != null && SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
final FilePath filePath = myFactory.createFilePathOnDeleted(wcPath, false);
|
||||
final SvnContentRevision beforeRevision = SvnContentRevision.createBaseRevision(myVcs, filePath, status.getRevision());
|
||||
final ContentRevision afterRevision = CurrentContentRevision.create(copiedFile.getFilePath());
|
||||
builder.processChangeInList(context.createMovedChange(beforeRevision, afterRevision, copiedStatus, status), changeListNameFromStatus(status),
|
||||
SvnVcs17.getKey());
|
||||
foundRename = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundRename) {
|
||||
// for debug
|
||||
LOG.info("Rename not found for " + copiedFile.getFilePath().getPresentableUrl());
|
||||
context.processStatus(copiedFile.getFilePath(), copiedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private SvnContentRevision createBeforeRevision(final SvnChangedFile changedFile, final boolean forDeleted) {
|
||||
return SvnContentRevision.createBaseRevision(myVcs,
|
||||
forDeleted ? FilePathImpl.createForDeletedFile(changedFile.getStatus().getFile(),
|
||||
changedFile.getFilePath().isDirectory()) :
|
||||
changedFile.getFilePath(), changedFile.getStatus().getRevision());
|
||||
}
|
||||
|
||||
private static File guessWorkingCopyPath(final File file, @NotNull final SVNURL url, final String copyFromURL) throws SVNException {
|
||||
String copiedPath = url.getPath();
|
||||
String copyFromPath = SVNURL.parseURIEncoded(copyFromURL).getPath();
|
||||
String commonPathAncestor = SVNPathUtil.getCommonPathAncestor(copiedPath, copyFromPath);
|
||||
int pathSegmentCount = SVNPathUtil.getSegmentsCount(copiedPath);
|
||||
int ancestorSegmentCount = SVNPathUtil.getSegmentsCount(commonPathAncestor);
|
||||
boolean startsWithSlash = file.getAbsolutePath().startsWith("/");
|
||||
List<String> segments = StringUtil.split(file.getPath(), File.separator);
|
||||
List<String> copyFromPathSegments = StringUtil.split(copyFromPath, "/");
|
||||
List<String> resultSegments = new ArrayList<String>();
|
||||
final int keepSegments = segments.size() - pathSegmentCount + ancestorSegmentCount;
|
||||
for(int i=0; i< keepSegments; i++) {
|
||||
resultSegments.add(segments.get(i));
|
||||
}
|
||||
for(int i=ancestorSegmentCount; i<copyFromPathSegments.size(); i++) {
|
||||
resultSegments.add(copyFromPathSegments.get(i));
|
||||
}
|
||||
|
||||
String result = StringUtil.join(resultSegments, "/");
|
||||
if (startsWithSlash) {
|
||||
result = "/" + result;
|
||||
}
|
||||
return new File(result);
|
||||
}
|
||||
|
||||
public boolean isModifiedDocumentTrackingRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void doCleanup(final List<VirtualFile> files) {
|
||||
new CleanupWorker(VfsUtil.toVirtualFileArray(files), myVcs.getProject(), "action.Subversion.cleanup.progress.title").execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNLock;
|
||||
import org.tmatesoft.svn.core.SVNNodeKind;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
class SvnChangeProviderContext implements StatusReceiver {
|
||||
private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.SvnChangeProviderContext");
|
||||
|
||||
private final ChangelistBuilder myChangelistBuilder;
|
||||
private final SVNStatusClient myStatusClient;
|
||||
private List<SvnChangedFile> myCopiedFiles = null;
|
||||
private final List<SvnChangedFile> myDeletedFiles = new ArrayList<SvnChangedFile>();
|
||||
// for files moved in a subtree, which were the targets of merge (for instance).
|
||||
private final Map<String, SVNStatus> myTreeConflicted;
|
||||
private Map<FilePath, String> myCopyFromURLs = null;
|
||||
private final SvnVcs17 myVcs;
|
||||
private final SvnBranchConfigurationManager17 myBranchConfigurationManager;
|
||||
|
||||
private final ProgressIndicator myProgress;
|
||||
|
||||
public SvnChangeProviderContext(SvnVcs17 vcs, final ChangelistBuilder changelistBuilder, final ProgressIndicator progress) {
|
||||
myVcs = vcs;
|
||||
myStatusClient = vcs.createStatusClient();
|
||||
myChangelistBuilder = changelistBuilder;
|
||||
myProgress = progress;
|
||||
myTreeConflicted = new HashMap<String, SVNStatus>();
|
||||
myBranchConfigurationManager = SvnBranchConfigurationManager17.getInstance(myVcs.getProject());
|
||||
}
|
||||
|
||||
public void process(FilePath path, SVNStatus status, boolean isInnerCopyRoot) throws SVNException {
|
||||
processStatusFirstPass(path, status);
|
||||
}
|
||||
|
||||
public void processIgnored(VirtualFile vFile) {
|
||||
myChangelistBuilder.processIgnoredFile(vFile);
|
||||
}
|
||||
|
||||
public void processUnversioned(VirtualFile vFile) {
|
||||
myChangelistBuilder.processUnversionedFile(vFile);
|
||||
}
|
||||
|
||||
public ChangelistBuilder getBuilder() {
|
||||
return myChangelistBuilder;
|
||||
}
|
||||
|
||||
public SVNStatusClient getClient() {
|
||||
return myStatusClient;
|
||||
}
|
||||
|
||||
public void reportTreeConflict(final SVNStatus status) {
|
||||
myTreeConflicted.put(status.getFile().getAbsolutePath(), status);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SVNStatus getTreeConflictStatus(final File file) {
|
||||
return myTreeConflicted.get(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<SvnChangedFile> getCopiedFiles() {
|
||||
if (myCopiedFiles == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return myCopiedFiles;
|
||||
}
|
||||
|
||||
public List<SvnChangedFile> getDeletedFiles() {
|
||||
return myDeletedFiles;
|
||||
}
|
||||
|
||||
public boolean isDeleted(final FilePath path) {
|
||||
for (SvnChangedFile deletedFile : myDeletedFiles) {
|
||||
if (Comparing.equal(path, deletedFile.getFilePath())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
return (myProgress != null) && myProgress.isCanceled();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the specified filepath or its parent was added with history, returns the URL of the copy source for this filepath.
|
||||
*
|
||||
* @param filePath the original filepath
|
||||
* @return the copy source url, or null if the file isn't a copy of anything
|
||||
*/
|
||||
@Nullable
|
||||
public String getParentCopyFromURL(FilePath filePath) {
|
||||
if (myCopyFromURLs == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder relPathBuilder = new StringBuilder();
|
||||
while(filePath != null) {
|
||||
String copyFromURL = myCopyFromURLs.get(filePath);
|
||||
if (copyFromURL != null) {
|
||||
return copyFromURL + relPathBuilder.toString();
|
||||
}
|
||||
relPathBuilder.insert(0, "/" + filePath.getName());
|
||||
filePath = filePath.getParentPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addCopiedFile(final FilePath filePath, final SVNStatus status, final String copyFromURL) {
|
||||
if (myCopiedFiles == null) {
|
||||
myCopiedFiles = new ArrayList<SvnChangedFile>();
|
||||
}
|
||||
myCopiedFiles.add(new SvnChangedFile(filePath, status, copyFromURL));
|
||||
final String url = status.getCopyFromURL();
|
||||
if (url != null) {
|
||||
addCopyFromURL(filePath, url);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCopyFromURL(final FilePath filePath, final String url) {
|
||||
if (myCopyFromURLs == null) {
|
||||
myCopyFromURLs = new HashMap<FilePath, String>();
|
||||
}
|
||||
myCopyFromURLs.put(filePath, url);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void processStatusFirstPass(final FilePath filePath, final SVNStatus status) throws SVNException {
|
||||
if (status == null) {
|
||||
// external to wc
|
||||
return;
|
||||
}
|
||||
if (status.getRemoteLock() != null) {
|
||||
final SVNLock lock = status.getRemoteLock();
|
||||
myChangelistBuilder.processLogicallyLockedFolder(filePath.getVirtualFile(),
|
||||
new LogicalLock(false, lock.getOwner(), lock.getComment(), lock.getCreationDate(), lock.getExpirationDate()));
|
||||
}
|
||||
if (status.getLocalLock() != null) {
|
||||
final SVNLock lock = status.getLocalLock();
|
||||
myChangelistBuilder.processLogicallyLockedFolder(filePath.getVirtualFile(),
|
||||
new LogicalLock(true, lock.getOwner(), lock.getComment(), lock.getCreationDate(), lock.getExpirationDate()));
|
||||
}
|
||||
if (filePath.isDirectory() && status.isLocked()) {
|
||||
myChangelistBuilder.processLockedFolder(filePath.getVirtualFile());
|
||||
}
|
||||
if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_ADDED) && status.getCopyFromURL() != null) {
|
||||
addCopiedFile(filePath, status, status.getCopyFromURL());
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
myDeletedFiles.add(new SvnChangedFile(filePath, status));
|
||||
}
|
||||
else {
|
||||
String parentCopyFromURL = getParentCopyFromURL(filePath);
|
||||
if (parentCopyFromURL != null) {
|
||||
addCopiedFile(filePath, status, parentCopyFromURL);
|
||||
} else {
|
||||
processStatus(filePath, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processStatus(final FilePath filePath, final SVNStatus status) throws SVNException {
|
||||
loadEntriesFile(filePath);
|
||||
if (status != null) {
|
||||
FileStatus fStatus = SvnStatusConvertor.convertStatus(status);
|
||||
|
||||
final SVNStatusType statusType = status.getContentsStatus();
|
||||
final SVNStatusType propStatus = status.getPropertiesStatus();
|
||||
if (SvnVcs17.svnStatusIsUnversioned(status) || SvnVcs17.svnStatusIs(status, SVNStatusType.UNKNOWN)) {
|
||||
final VirtualFile file = filePath.getVirtualFile();
|
||||
if (file != null) {
|
||||
myChangelistBuilder.processUnversionedFile(file);
|
||||
}
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_ADDED)) {
|
||||
myChangelistBuilder.processChangeInList(createChange(null, CurrentContentRevision.create(filePath), fStatus, status),
|
||||
changeListNameFromStatus(status), SvnVcs17.getKey());
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_CONFLICTED) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_MODIFIED) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_REPLACED) ||
|
||||
propStatus == SVNStatusType.STATUS_MODIFIED ||
|
||||
propStatus == SVNStatusType.STATUS_CONFLICTED) {
|
||||
myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, status.getRevision()),
|
||||
CurrentContentRevision.create(filePath), fStatus, status), changeListNameFromStatus(status), SvnVcs17.getKey());
|
||||
checkSwitched(filePath, myChangelistBuilder, status, fStatus);
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
myChangelistBuilder.processChangeInList(
|
||||
createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, status.getRevision()), null, fStatus, status),
|
||||
changeListNameFromStatus(status), SvnVcs17.getKey());
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_MISSING)) {
|
||||
myChangelistBuilder.processLocallyDeletedFile(createLocallyDeletedChange(filePath, status));
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_IGNORED)) {
|
||||
myChangelistBuilder.processIgnoredFile(filePath.getVirtualFile());
|
||||
}
|
||||
else if (status.isCopied()) {
|
||||
//
|
||||
}
|
||||
else if ((fStatus == FileStatus.NOT_CHANGED || fStatus == FileStatus.SWITCHED) && statusType != SVNStatusType.STATUS_NONE) {
|
||||
VirtualFile file = filePath.getVirtualFile();
|
||||
if (file != null && FileDocumentManager.getInstance().isFileModified(file)) {
|
||||
myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, status.getRevision()),
|
||||
CurrentContentRevision.create(filePath), FileStatus.MODIFIED, status), changeListNameFromStatus(status),
|
||||
SvnVcs17.getKey());
|
||||
} else if (status.getTreeConflict() != null) {
|
||||
myChangelistBuilder.processChange(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, status.getRevision()),
|
||||
CurrentContentRevision.create(filePath), FileStatus.MODIFIED, status), SvnVcs17.getKey());
|
||||
}
|
||||
checkSwitched(filePath, myChangelistBuilder, status, fStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addModifiedNotSavedChange(final VirtualFile file) throws SVNException {
|
||||
final FilePath filePath = new FilePathImpl(file);
|
||||
final SVNInfo svnInfo;
|
||||
try {
|
||||
svnInfo = myVcs.createWCClient().doInfo(new File(file.getPath()), SVNRevision.UNDEFINED);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
if (SVNErrorCode.WC_PATH_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) {
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
final SVNStatus svnStatus = new SVNStatus();
|
||||
svnStatus.setRevision(svnInfo.getRevision());
|
||||
myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, svnInfo.getRevision()),
|
||||
CurrentContentRevision.create(filePath), FileStatus.MODIFIED, svnStatus), (String) null,
|
||||
SvnVcs17.getKey());
|
||||
}
|
||||
|
||||
private void checkSwitched(final FilePath filePath, final ChangelistBuilder builder, final SVNStatus status,
|
||||
final FileStatus convertedStatus) {
|
||||
if (status.isSwitched() || (convertedStatus == FileStatus.SWITCHED)) {
|
||||
final VirtualFile virtualFile = filePath.getVirtualFile();
|
||||
if (virtualFile == null) return;
|
||||
final String switchUrl = status.getURL().toString();
|
||||
final VirtualFile vcsRoot = ProjectLevelVcsManager.getInstance(myVcs.getProject()).getVcsRootFor(virtualFile);
|
||||
if (vcsRoot != null) { // it will be null if we walked into an excluded directory
|
||||
String baseUrl = null;
|
||||
try {
|
||||
baseUrl = myBranchConfigurationManager.get(vcsRoot).getBaseName(switchUrl);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
builder.processSwitchedFile(virtualFile, baseUrl == null ? switchUrl : baseUrl, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the contents of the 'entries' file is cached in the VFS, so that the VFS will send
|
||||
* correct events when the 'entries' file is changed externally (to be received by SvnEntriesFileListener)
|
||||
*
|
||||
* @param filePath the path of a changed file.
|
||||
*/
|
||||
private static void loadEntriesFile(final FilePath filePath) {
|
||||
final FilePath parentPath = filePath.getParentPath();
|
||||
if (parentPath == null) {
|
||||
return;
|
||||
}
|
||||
File svnSubdirectory = new File(parentPath.getIOFile(), SvnUtil.SVN_ADMIN_DIR_NAME);
|
||||
LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
|
||||
VirtualFile file = localFileSystem.refreshAndFindFileByIoFile(svnSubdirectory);
|
||||
if (file != null) {
|
||||
localFileSystem.refreshAndFindFileByIoFile(new File(svnSubdirectory, SvnUtil.ENTRIES_FILE_NAME));
|
||||
}
|
||||
if (filePath.isDirectory()) {
|
||||
svnSubdirectory = new File(filePath.getPath(), SvnUtil.SVN_ADMIN_DIR_NAME);
|
||||
file = localFileSystem.refreshAndFindFileByIoFile(svnSubdirectory);
|
||||
if (file != null) {
|
||||
localFileSystem.refreshAndFindFileByIoFile(new File(svnSubdirectory, SvnUtil.ENTRIES_FILE_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// seems here we can only have a tree conflict; which can be marked on either path (?)
|
||||
// .. ok try to merge states
|
||||
Change createMovedChange(final ContentRevision before, final ContentRevision after, final SVNStatus copiedStatus,
|
||||
final SVNStatus deletedStatus) {
|
||||
return new ConflictedSvnChange(before, after, ConflictState.mergeState(getState(copiedStatus), getState(deletedStatus)),
|
||||
((copiedStatus != null) && (copiedStatus.getTreeConflict() != null)) ? after.getFile() : before.getFile());
|
||||
}
|
||||
|
||||
private Change createChange(final ContentRevision before, final ContentRevision after, final FileStatus fStatus, final SVNStatus svnStatus) {
|
||||
return new ConflictedSvnChange(before, after, fStatus, getState(svnStatus), after == null ? before.getFile() : after.getFile());
|
||||
}
|
||||
|
||||
private LocallyDeletedChange createLocallyDeletedChange(@NotNull FilePath filePath, final SVNStatus status) {
|
||||
return new SvnLocallyDeletedChange(filePath, getState(status));
|
||||
}
|
||||
|
||||
private ConflictState getState(@Nullable final SVNStatus svnStatus) {
|
||||
if (svnStatus == null) {
|
||||
return ConflictState.none;
|
||||
}
|
||||
|
||||
final boolean treeConflict = svnStatus.getTreeConflict() != null;
|
||||
final boolean textConflict = SVNStatusType.STATUS_CONFLICTED == svnStatus.getContentsStatus();
|
||||
final boolean propertyConflict = SVNStatusType.STATUS_CONFLICTED == svnStatus.getPropertiesStatus();
|
||||
if (treeConflict) {
|
||||
reportTreeConflict(svnStatus);
|
||||
}
|
||||
|
||||
return ConflictState.getInstance(treeConflict, textConflict, propertyConflict);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String changeListNameFromStatus(final SVNStatus status) {
|
||||
if (WorkingCopyFormat.getInstance(status.getWorkingCopyFormat()).supportsChangelists()) {
|
||||
if (SVNNodeKind.FILE.equals(status.getKind())) {
|
||||
final String clName = status.getChangelistName();
|
||||
return (clName == null) ? null : clName;
|
||||
}
|
||||
}
|
||||
// always null for earlier versions
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
|
||||
class SvnChangedFile {
|
||||
private final FilePath myFilePath;
|
||||
private final SVNStatus myStatus;
|
||||
private String myCopyFromURL;
|
||||
|
||||
public SvnChangedFile(final FilePath filePath, final SVNStatus status) {
|
||||
myFilePath = filePath;
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
public SvnChangedFile(final FilePath filePath, final SVNStatus status, final String copyFromURL) {
|
||||
myFilePath = filePath;
|
||||
myStatus = status;
|
||||
myCopyFromURL = copyFromURL;
|
||||
}
|
||||
|
||||
public FilePath getFilePath() {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
public SVNStatus getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
public String getCopyFromURL() {
|
||||
if (myCopyFromURL == null) {
|
||||
return myStatus.getCopyFromURL();
|
||||
}
|
||||
return myCopyFromURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myFilePath.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final SvnChangedFile that = (SvnChangedFile)o;
|
||||
|
||||
if (myFilePath != null ? !myFilePath.equals(that.myFilePath) : that.myFilePath != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myFilePath != null ? myFilePath.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListListener;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNChangelistHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNChangelistClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class SvnChangelistListener implements ChangeListListener {
|
||||
private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnChangelistListener");
|
||||
|
||||
private final Project myProject;
|
||||
private final SVNChangelistClient myClient;
|
||||
|
||||
public SvnChangelistListener(final Project project, final SVNChangelistClient client) {
|
||||
myProject = project;
|
||||
myClient = client;
|
||||
}
|
||||
|
||||
public void changeListAdded(final ChangeList list) {
|
||||
// SVN change list exists only when there are any files in it
|
||||
}
|
||||
|
||||
public void changesRemoved(final Collection<Change> changes, final ChangeList fromList) {
|
||||
if (SvnChangeProvider.ourDefaultListName.equals(fromList.getName())) {
|
||||
return;
|
||||
}
|
||||
final List<String> paths = getPathsFromChanges(changes);
|
||||
for (String path : paths) {
|
||||
try {
|
||||
myClient.doRemoveFromChangelist(new File[]{new File(path)}, SVNDepth.EMPTY, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void changesAdded(Collection<Change> changes, ChangeList toList) {
|
||||
if (toList == null) return;
|
||||
if (SvnChangeProvider.ourDefaultListName.equals(toList.getName())) {
|
||||
return;
|
||||
}
|
||||
final List<String> paths = getPathsFromChanges(changes);
|
||||
for (String path : paths) {
|
||||
try {
|
||||
myClient.doAddToChangelist(new File[]{new File(path)}, SVNDepth.EMPTY, toList.getName(), null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void changeListRemoved(final ChangeList list) {
|
||||
final List<String> paths = getPathsFromChanges(list.getChanges());
|
||||
for (String path : paths) {
|
||||
try {
|
||||
myClient.doRemoveFromChangelist(new File[]{new File(path)}, SVNDepth.EMPTY, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnderSvn(final FilePath path) {
|
||||
final AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(path);
|
||||
return ((vcs != null) && (SvnVcs17.VCS_NAME.equals(vcs.getName())));
|
||||
}
|
||||
|
||||
private List<String> getPathsFromChanges(final Collection<Change> changes) {
|
||||
final List<String> paths = new ArrayList<String>();
|
||||
for (Change change : changes) {
|
||||
if ((change.getBeforeRevision() != null) && (isUnderSvn(change.getBeforeRevision().getFile()))) {
|
||||
final String path = change.getBeforeRevision().getFile().getIOFile().getAbsolutePath();
|
||||
if (! paths.contains(path)) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
if ((change.getAfterRevision() != null) && (isUnderSvn(change.getAfterRevision().getFile()))) {
|
||||
final String path = change.getAfterRevision().getFile().getIOFile().getAbsolutePath();
|
||||
if (! paths.contains(path)) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
public void changeListChanged(final ChangeList list) {
|
||||
}
|
||||
|
||||
public void changeListRenamed(final ChangeList list, final String oldName) {
|
||||
if (Comparing.equal(list.getName(), oldName)) {
|
||||
return;
|
||||
}
|
||||
if (SvnChangeProvider.ourDefaultListName.equals(list.getName())) {
|
||||
changeListRemoved(list);
|
||||
return;
|
||||
}
|
||||
final List<String> paths = getPathsFromChanges(list.getChanges());
|
||||
for (String path : paths) {
|
||||
try {
|
||||
myClient.doAddToChangelist(new File[]{new File(path)}, SVNDepth.EMPTY, list.getName(), null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void changeListCommentChanged(final ChangeList list, final String oldComment) {
|
||||
}
|
||||
|
||||
public void changesMoved(final Collection<Change> changes, final ChangeList fromList, final ChangeList toList) {
|
||||
if (fromList.getName().equals(toList.getName())) {
|
||||
return;
|
||||
}
|
||||
if (SvnChangeProvider.ourDefaultListName.equals(toList.getName())) {
|
||||
changeListRemoved(toList);
|
||||
return;
|
||||
}
|
||||
final String[] fromLists = SvnChangeProvider.ourDefaultListName.equals(fromList.getName()) ? null : new String[] {fromList.getName()};
|
||||
final List<String> paths = getPathsFromChanges(changes);
|
||||
for (final String path : paths) {
|
||||
try {
|
||||
myClient.doAddToChangelist(new File[]{new File(path)}, SVNDepth.EMPTY, toList.getName(), fromLists);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void defaultListChanged(final ChangeList oldDefaultList, final ChangeList newDefaultList) {
|
||||
}
|
||||
|
||||
public void unchangedFileStatusChanged() {
|
||||
}
|
||||
|
||||
public void changeListUpdateDone() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getCurrentMapping(final Project project, final File file) {
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
final SVNChangelistClient client = vcs.createChangelistClient();
|
||||
try {
|
||||
final Ref<String> refResult = new Ref<String>();
|
||||
final ISVNChangelistHandler handler = new ISVNChangelistHandler() {
|
||||
public void handle(final File path, final String changelistName) {
|
||||
if (refResult.isNull() && Comparing.equal(path, file)) {
|
||||
refResult.set(changelistName);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (file.exists()) {
|
||||
client.doGetChangeLists(file, null, SVNDepth.EMPTY, handler);
|
||||
} else if (file.getParentFile() != null) {
|
||||
client.doGetChangeLists(file.getParentFile(), null, SVNDepth.IMMEDIATES, handler);
|
||||
}
|
||||
return refResult.get();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
final SVNErrorCode errorCode = e.getErrorMessage().getErrorCode();
|
||||
if (SVNErrorCode.WC_NOT_DIRECTORY.equals(errorCode) || SVNErrorCode.WC_NOT_FILE.equals(errorCode)) {
|
||||
LOG.debug("Logging only, exception is valid (caught) here", e);
|
||||
} else {
|
||||
LOG.info("Logging only, exception is valid (caught) here", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void putUnderList(final Project project, final String list, final File after) throws SVNException {
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
final SVNChangelistClient client = vcs.createChangelistClient();
|
||||
try {
|
||||
client.doAddToChangelist(new File[]{after}, SVNDepth.EMPTY, list, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
if ((! SVNErrorCode.WC_NOT_DIRECTORY.equals(e.getErrorMessage().getErrorCode()) && (! SVNErrorCode.WC_NOT_FILE.equals(e.getErrorMessage().getErrorCode())))) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeFromList(final Project project, final File after) throws SVNException {
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
final SVNChangelistClient client = vcs.createChangelistClient();
|
||||
try {
|
||||
client.doRemoveFromChangelist(new File[]{after}, SVNDepth.EMPTY, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
if ((! SVNErrorCode.WC_NOT_DIRECTORY.equals(e.getErrorMessage().getErrorCode()) && (! SVNErrorCode.WC_NOT_FILE.equals(e.getErrorMessage().getErrorCode())))) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SvnCompatibilityChecker {
|
||||
private final Project myProject;
|
||||
private final static long ourFrequency = 10;
|
||||
private final static long ourInvocationMax = 10;
|
||||
private final static long ourInitCounter = 3;
|
||||
|
||||
private long myCounter;
|
||||
private long myDownStartCounter;
|
||||
private long myInvocationCounter;
|
||||
|
||||
private final Object myLock = new Object();
|
||||
|
||||
public SvnCompatibilityChecker(Project project) {
|
||||
myProject = project;
|
||||
myCounter= 0;
|
||||
myDownStartCounter = ourInitCounter;
|
||||
myInvocationCounter = 0;
|
||||
}
|
||||
|
||||
public void reportNoRoots(final List<VirtualFile> result) {
|
||||
synchronized (myLock) {
|
||||
if (myInvocationCounter >= ourInvocationMax) return;
|
||||
++ myCounter;
|
||||
-- myDownStartCounter;
|
||||
if ((myCounter > ourFrequency) || (myDownStartCounter >= 0)) {
|
||||
myCounter = 0;
|
||||
++ myInvocationCounter;
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
final List<VirtualFile> suspicious = new ArrayList<VirtualFile>();
|
||||
for (VirtualFile vf : result) {
|
||||
if (SvnUtil.seemsLikeVersionedDir(vf)) {
|
||||
suspicious.add(vf);
|
||||
}
|
||||
}
|
||||
if (! suspicious.isEmpty()) {
|
||||
final String message = (suspicious.size() == 1) ?
|
||||
"Root '" + suspicious.get(0).getPresentableName() + "' is likely to be of unsupported Subversion format" :
|
||||
"Some roots are likely to be of unsupported Subversion format";
|
||||
application.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new VcsBalloonProblemNotifier(myProject, message, MessageType.WARNING).run();
|
||||
}
|
||||
}, ModalityState.NON_MODAL, new Condition() {
|
||||
@Override
|
||||
public boolean value(Object o) {
|
||||
return (! myProject.isOpen()) || myProject.isDisposed();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.idea.svn17.SvnConfigurable">
|
||||
<grid id="27dc6" binding="myComponent" layout-manager="GridLayoutManager" row-count="22" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="959" height="651"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="76b6e">
|
||||
<constraints>
|
||||
<grid row="21" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="5" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="9b7ff" class="javax.swing.JLabel" binding="myConfigurationDirectoryLabel">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="319" height="16"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="label.configuration.configuration.directory"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="212b3" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myConfigurationDirectoryText">
|
||||
<constraints>
|
||||
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="319" height="28"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<editable value="false"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="df054" class="javax.swing.JCheckBox" binding="myUseDefaultCheckBox">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="319" height="23"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="checkbox.configure.use.system.default.configuration.directory"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="1283d" class="javax.swing.JCheckBox" binding="myUseCommonProxy">
|
||||
<constraints>
|
||||
<grid row="10" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="319" height="23"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Use IDEA general proxy settings as default for Subversion" noi18n="true"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="3e7c5" class="javax.swing.JButton" binding="myEditProxiesButton">
|
||||
<constraints>
|
||||
<grid row="13" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="button.text.edit.proxies"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="decc5" class="javax.swing.JButton" binding="myClearAuthButton">
|
||||
<constraints>
|
||||
<grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="button.text.clear.authentication.cache"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="23675" class="javax.swing.JLabel" binding="myClearCacheLabel">
|
||||
<constraints>
|
||||
<grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
<font/>
|
||||
<foreground color="-10066330"/>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="label.text.delete.stored.credentials"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="a9606" class="javax.swing.JLabel" binding="myUseCommonProxyLabel">
|
||||
<constraints>
|
||||
<grid row="11" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
<foreground color="-10066330"/>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="use.idea.proxy.as.default.label.text"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="a353c" class="javax.swing.JLabel" binding="myEditProxyLabel">
|
||||
<constraints>
|
||||
<grid row="14" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
<foreground color="-10066330"/>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="label.text.edit.proxies"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="27350" class="com.intellij.ui.TitledSeparator">
|
||||
<constraints>
|
||||
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="2" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="b92b0" class="com.intellij.ui.TitledSeparator">
|
||||
<constraints>
|
||||
<grid row="9" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="2" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="14e00" class="com.intellij.ui.TitledSeparator">
|
||||
<constraints>
|
||||
<grid row="12" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="2" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="947fd" class="javax.swing.JCheckBox" binding="myLockOnDemand" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="action.Subversion.update.use.locks.on.demand.text.configurable"/>
|
||||
<toolTipText resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="action.Subversion.update.use.locks.on.demand.description"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="c2f81" class="javax.swing.JCheckBox" binding="myDetectNestedWorkingCopiesCheckBox" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="15" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="detect.nested.working.copies"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="f2afc" class="javax.swing.JCheckBox" binding="myIgnoreWhitespaceDifferenciesInCheckBox" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="19" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="svn.option.ignore.whitespace.in.annotate"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="cd5ae" class="javax.swing.JCheckBox" binding="myShowMergeSourceInAnnotate" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="18" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="annotation.show.merge.sources.default.text"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="fa93d" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="17" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<hspacer id="44294">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<component id="aa58e" class="javax.swing.JSpinner" binding="myNumRevsInAnnotations" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="a1351" class="javax.swing.JCheckBox" binding="myMaximumNumberOfRevisionsCheckBox" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Maximum number of revisions to look back in annotations"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="41718" class="javax.swing.JCheckBox" binding="myCheckNestedInQuickMerge">
|
||||
<constraints>
|
||||
<grid row="16" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Check svn:mergeinfo in target subtree when preparing for merge"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="dace9" layout-manager="GridLayoutManager" row-count="2" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="20" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="234" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="SSH connection timeout:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="ca199">
|
||||
<constraints>
|
||||
<grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<component id="21604" class="javax.swing.JSpinner" binding="mySSHConnectionTimeout" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="44801" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="SSH read timeout:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="8e59f" class="javax.swing.JSpinner" binding="mySSHReadTimeout" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<hspacer id="8e62f">
|
||||
<constraints>
|
||||
<grid row="1" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<component id="b9617" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="seconds"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="732b" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="seconds"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<hspacer id="72c3d">
|
||||
<constraints>
|
||||
<grid row="20" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<component id="33d81" class="com.intellij.ui.components.JBLabel" binding="myWarningLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<foreground color="-65536"/>
|
||||
<text resource-bundle="org/jetbrains/idea/svn17/SvnBundle" key="svn17.plugin.not.ready"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="f7ade" class="com.intellij.ui.HyperlinkLabel" binding="myLinkLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.ui.HyperlinkLabel;
|
||||
import com.intellij.ui.MultiLineTooltipUI;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.idea.svn17.config.ConfigureProxiesListener;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
||||
public class SvnConfigurable implements Configurable {
|
||||
|
||||
private final Project myProject;
|
||||
private JCheckBox myUseDefaultCheckBox;
|
||||
private TextFieldWithBrowseButton myConfigurationDirectoryText;
|
||||
private JButton myClearAuthButton;
|
||||
private JCheckBox myUseCommonProxy;
|
||||
private JButton myEditProxiesButton;
|
||||
private JPanel myComponent;
|
||||
|
||||
private JLabel myConfigurationDirectoryLabel;
|
||||
private JLabel myClearCacheLabel;
|
||||
private JLabel myUseCommonProxyLabel;
|
||||
private JLabel myEditProxyLabel;
|
||||
private JCheckBox myLockOnDemand;
|
||||
private JCheckBox myCheckNestedInQuickMerge;
|
||||
private JCheckBox myDetectNestedWorkingCopiesCheckBox;
|
||||
private JCheckBox myIgnoreWhitespaceDifferenciesInCheckBox;
|
||||
private JCheckBox myShowMergeSourceInAnnotate;
|
||||
private JSpinner myNumRevsInAnnotations;
|
||||
private JCheckBox myMaximumNumberOfRevisionsCheckBox;
|
||||
private JSpinner mySSHConnectionTimeout;
|
||||
private JSpinner mySSHReadTimeout;
|
||||
private JBLabel myWarningLabel;
|
||||
private HyperlinkLabel myLinkLabel;
|
||||
|
||||
@NonNls private static final String HELP_ID = "project.propSubversion";
|
||||
|
||||
public SvnConfigurable(Project project) {
|
||||
myProject = project;
|
||||
myLinkLabel.setHyperlinkTarget("http://youtrack.jetbrains.net/issue/IDEA-72400");
|
||||
myLinkLabel.setHyperlinkText("More information");
|
||||
|
||||
myUseDefaultCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
boolean enabled = !myUseDefaultCheckBox.isSelected();
|
||||
myConfigurationDirectoryText.setEnabled(enabled);
|
||||
myConfigurationDirectoryLabel.setEnabled(enabled);
|
||||
SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myProject);
|
||||
String path = configuration.getConfigurationDirectory();
|
||||
if (!enabled || path == null) {
|
||||
myConfigurationDirectoryText.setText(IdeaSubversionConfigurationDirectory.getPath());
|
||||
}
|
||||
else {
|
||||
myConfigurationDirectoryText.setText(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myClearAuthButton.addActionListener(new ActionListener(){
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
String path = myConfigurationDirectoryText.getText();
|
||||
if (path != null) {
|
||||
int result = Messages.showYesNoDialog(myComponent, SvnBundle.message("confirmation.text.delete.stored.authentication.information"),
|
||||
SvnBundle.message("confirmation.title.clear.authentication.cache"),
|
||||
Messages.getWarningIcon());
|
||||
if (result == 0) {
|
||||
SvnConfiguration17.RUNTIME_AUTH_CACHE.clear();
|
||||
SvnConfiguration17.getInstance(myProject).clearAuthenticationDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
final FileChooserDescriptor descriptor = createFileDescriptor();
|
||||
|
||||
myConfigurationDirectoryText.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@NonNls String path = myConfigurationDirectoryText.getText().trim();
|
||||
path = "file://" + path.replace(File.separatorChar, '/');
|
||||
VirtualFile root = VirtualFileManager.getInstance().findFileByUrl(path);
|
||||
|
||||
String oldValue = PropertiesComponent.getInstance().getValue("FileChooser.showHiddens");
|
||||
PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", Boolean.TRUE.toString());
|
||||
VirtualFile file = FileChooser.chooseFile(myComponent, descriptor, root);
|
||||
PropertiesComponent.getInstance().setValue("FileChooser.showHiddens", oldValue);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
myConfigurationDirectoryText.setText(file.getPath().replace('/', File.separatorChar));
|
||||
}
|
||||
});
|
||||
myConfigurationDirectoryText.setEditable(false);
|
||||
|
||||
myConfigurationDirectoryLabel.setLabelFor(myConfigurationDirectoryText);
|
||||
|
||||
myUseCommonProxy.setText(SvnBundle.message("use.idea.proxy.as.default", ApplicationNamesInfo.getInstance().getProductName()));
|
||||
myEditProxiesButton.addActionListener(new ConfigureProxiesListener(myProject));
|
||||
|
||||
myMaximumNumberOfRevisionsCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
|
||||
}
|
||||
});
|
||||
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
|
||||
}
|
||||
|
||||
private static FileChooserDescriptor createFileDescriptor() {
|
||||
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
|
||||
descriptor.setShowFileSystemRoots(true);
|
||||
descriptor.setTitle(SvnBundle.message("dialog.title.select.configuration.directory"));
|
||||
descriptor.setDescription(SvnBundle.message("dialog.description.select.configuration.directory"));
|
||||
descriptor.setHideIgnored(false);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public JComponent createComponent() {
|
||||
|
||||
return myComponent;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getHelpTopic() {
|
||||
return HELP_ID;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
if (myComponent == null) {
|
||||
return false;
|
||||
}
|
||||
SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myProject);
|
||||
if (configuration.isUseDefaultConfiguation() != myUseDefaultCheckBox.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.isIsUseDefaultProxy() != myUseCommonProxy.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.UPDATE_LOCK_ON_DEMAND != myLockOnDemand.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.DETECT_NESTED_COPIES != myDetectNestedWorkingCopiesCheckBox.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.CHECK_NESTED_FOR_QUICK_MERGE != myCheckNestedInQuickMerge.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.IGNORE_SPACES_IN_ANNOTATE != myIgnoreWhitespaceDifferenciesInCheckBox.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.SHOW_MERGE_SOURCES_IN_ANNOTATE != myShowMergeSourceInAnnotate.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
final int annotateRevisions = configuration.getMaxAnnotateRevisions();
|
||||
final boolean useMaxInAnnot = annotateRevisions != -1;
|
||||
if (useMaxInAnnot != myMaximumNumberOfRevisionsCheckBox.isSelected()) {
|
||||
return true;
|
||||
}
|
||||
if (myMaximumNumberOfRevisionsCheckBox.isSelected()) {
|
||||
if (annotateRevisions != ((SpinnerNumberModel) myNumRevsInAnnotations.getModel()).getNumber().intValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (configuration.mySSHConnectionTimeout/1000 != ((SpinnerNumberModel) mySSHConnectionTimeout.getModel()).getNumber().longValue()) {
|
||||
return true;
|
||||
}
|
||||
if (configuration.mySSHReadTimeout/1000 != ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue()) {
|
||||
return true;
|
||||
}
|
||||
return !configuration.getConfigurationDirectory().equals(myConfigurationDirectoryText.getText().trim());
|
||||
}
|
||||
|
||||
public void apply() throws ConfigurationException {
|
||||
SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myProject);
|
||||
configuration.setConfigurationDirectory(myConfigurationDirectoryText.getText());
|
||||
configuration.setUseDefaultConfiguation(myUseDefaultCheckBox.isSelected());
|
||||
configuration.setIsUseDefaultProxy(myUseCommonProxy.isSelected());
|
||||
if ((! configuration.DETECT_NESTED_COPIES) && (configuration.DETECT_NESTED_COPIES != myDetectNestedWorkingCopiesCheckBox.isSelected())) {
|
||||
SvnVcs17.getInstance(myProject).invokeRefreshSvnRoots(true);
|
||||
}
|
||||
configuration.DETECT_NESTED_COPIES = myDetectNestedWorkingCopiesCheckBox.isSelected();
|
||||
configuration.CHECK_NESTED_FOR_QUICK_MERGE = myCheckNestedInQuickMerge.isSelected();
|
||||
configuration.UPDATE_LOCK_ON_DEMAND = myLockOnDemand.isSelected();
|
||||
configuration.setIgnoreSpacesInAnnotate(myIgnoreWhitespaceDifferenciesInCheckBox.isSelected());
|
||||
configuration.SHOW_MERGE_SOURCES_IN_ANNOTATE = myShowMergeSourceInAnnotate.isSelected();
|
||||
if (! myMaximumNumberOfRevisionsCheckBox.isSelected()) {
|
||||
configuration.setMaxAnnotateRevisions(-1);
|
||||
} else {
|
||||
configuration.setMaxAnnotateRevisions(((SpinnerNumberModel) myNumRevsInAnnotations.getModel()).getNumber().intValue());
|
||||
}
|
||||
configuration.mySSHConnectionTimeout = ((SpinnerNumberModel) mySSHConnectionTimeout.getModel()).getNumber().longValue() * 1000;
|
||||
configuration.mySSHReadTimeout = ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue() * 1000;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myProject);
|
||||
String path = configuration.getConfigurationDirectory();
|
||||
if (configuration.isUseDefaultConfiguation() || path == null) {
|
||||
path = IdeaSubversionConfigurationDirectory.getPath();
|
||||
}
|
||||
myConfigurationDirectoryText.setText(path);
|
||||
myUseDefaultCheckBox.setSelected(configuration.isUseDefaultConfiguation());
|
||||
myUseCommonProxy.setSelected(configuration.isIsUseDefaultProxy());
|
||||
myDetectNestedWorkingCopiesCheckBox.setSelected(configuration.DETECT_NESTED_COPIES);
|
||||
myCheckNestedInQuickMerge.setSelected(configuration.CHECK_NESTED_FOR_QUICK_MERGE);
|
||||
|
||||
boolean enabled = !myUseDefaultCheckBox.isSelected();
|
||||
myConfigurationDirectoryText.setEnabled(enabled);
|
||||
myConfigurationDirectoryLabel.setEnabled(enabled);
|
||||
myLockOnDemand.setSelected(configuration.UPDATE_LOCK_ON_DEMAND);
|
||||
myIgnoreWhitespaceDifferenciesInCheckBox.setSelected(configuration.IGNORE_SPACES_IN_ANNOTATE);
|
||||
myShowMergeSourceInAnnotate.setSelected(configuration.SHOW_MERGE_SOURCES_IN_ANNOTATE);
|
||||
|
||||
final int annotateRevisions = configuration.getMaxAnnotateRevisions();
|
||||
if (annotateRevisions == -1) {
|
||||
myMaximumNumberOfRevisionsCheckBox.setSelected(false);
|
||||
myNumRevsInAnnotations.setValue(SvnConfiguration17.ourMaxAnnotateRevisionsDefault);
|
||||
} else {
|
||||
myMaximumNumberOfRevisionsCheckBox.setSelected(true);
|
||||
myNumRevsInAnnotations.setValue(annotateRevisions);
|
||||
}
|
||||
myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected());
|
||||
mySSHConnectionTimeout.setValue(Long.valueOf(configuration.mySSHConnectionTimeout / 1000));
|
||||
mySSHReadTimeout.setValue(Long.valueOf(configuration.mySSHReadTimeout / 1000));
|
||||
}
|
||||
|
||||
public void disposeUIResources() {
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
myLockOnDemand = new JCheckBox() {
|
||||
@Override
|
||||
public JToolTip createToolTip() {
|
||||
JToolTip toolTip = new JToolTip(){{
|
||||
setUI(new MultiLineTooltipUI());
|
||||
}};
|
||||
toolTip.setComponent(this);
|
||||
return toolTip;
|
||||
}
|
||||
};
|
||||
|
||||
final SvnConfiguration17 configuration = SvnConfiguration17.getInstance(myProject);
|
||||
int value = configuration.getMaxAnnotateRevisions();
|
||||
value = (value == -1) ? SvnConfiguration17.ourMaxAnnotateRevisionsDefault : value;
|
||||
myNumRevsInAnnotations = new JSpinner(new SpinnerNumberModel(value, 10, 100000, 100));
|
||||
|
||||
final int maximum = 30 * 60 * 1000;
|
||||
final long connection = configuration.mySSHConnectionTimeout <= maximum ? configuration.mySSHConnectionTimeout : maximum;
|
||||
final long read = configuration.mySSHReadTimeout <= maximum ? configuration.mySSHReadTimeout : maximum;
|
||||
mySSHConnectionTimeout = new JSpinner(new SpinnerNumberModel(Long.valueOf(connection / 1000).longValue(), 0, maximum, 10));
|
||||
mySSHReadTimeout = new JSpinner(new SpinnerNumberModel(Long.valueOf(read / 1000).longValue(), 0, maximum, 10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.annotate.AnnotationListener;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.DataConversionException;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.idea.svn17.dialogs.SvnAuthenticationProvider;
|
||||
import org.jetbrains.idea.svn17.dialogs.SvnInteractiveAuthenticationProvider;
|
||||
import org.jetbrains.idea.svn17.update.MergeRootInfo;
|
||||
import org.jetbrains.idea.svn17.update.UpdateRootInfo;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
|
||||
import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider;
|
||||
import org.tmatesoft.svn.core.auth.SVNAuthentication;
|
||||
import org.tmatesoft.svn.core.internal.wc.ISVNAuthenticationStorage;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNConfigFile;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
|
||||
import org.tmatesoft.svn.core.wc.ISVNOptions;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.*;
|
||||
|
||||
@State(
|
||||
name = "SvnConfiguration17",
|
||||
storages = {
|
||||
@Storage(
|
||||
file = "$WORKSPACE_FILE$"
|
||||
)
|
||||
}
|
||||
)
|
||||
public class SvnConfiguration17 implements PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.SvnConfiguration");
|
||||
public final static int ourMaxAnnotateRevisionsDefault = 500;
|
||||
|
||||
private final static String SERVERS_FILE_NAME = "servers";
|
||||
|
||||
public static final String UPGRADE_AUTO = "auto";
|
||||
public static final String UPGRADE_AUTO_15 = "auto1.5";
|
||||
public static final String UPGRADE_AUTO_16 = "auto1.6";
|
||||
public static final String UPGRADE_AUTO_17 = "auto1.7";
|
||||
public static final String UPGRADE_NONE = "none";
|
||||
|
||||
public String USER = "";
|
||||
public String PASSWORD = "";
|
||||
public String[] ADD_PATHS = null;
|
||||
|
||||
private String myConfigurationDirectory;
|
||||
private boolean myIsUseDefaultConfiguration;
|
||||
private boolean myIsUseDefaultProxy;
|
||||
private ISVNOptions myOptions;
|
||||
private boolean myIsKeepLocks;
|
||||
private boolean myRemoteStatus;
|
||||
private final Project myProject;
|
||||
private SvnAuthenticationManager myAuthManager;
|
||||
private SvnAuthenticationManager myPassiveAuthManager;
|
||||
private SvnAuthenticationManager myInteractiveManager;
|
||||
private String myUpgradeMode;
|
||||
private SvnSupportOptions mySupportOptions;
|
||||
private int myMaxAnnotateRevisions = ourMaxAnnotateRevisionsDefault;
|
||||
private final static long DEFAULT_SSH_TIMEOUT = 30 * 1000;
|
||||
public long mySSHConnectionTimeout = DEFAULT_SSH_TIMEOUT;
|
||||
public long mySSHReadTimeout = DEFAULT_SSH_TIMEOUT;
|
||||
|
||||
public static final AuthStorage RUNTIME_AUTH_CACHE = new AuthStorage();
|
||||
public String LAST_MERGED_REVISION = null;
|
||||
public SVNDepth UPDATE_DEPTH = SVNDepth.INFINITY;
|
||||
|
||||
public boolean MERGE_DRY_RUN = false;
|
||||
public boolean MERGE_DIFF_USE_ANCESTRY = true;
|
||||
public boolean UPDATE_LOCK_ON_DEMAND = false;
|
||||
public boolean IGNORE_SPACES_IN_MERGE = false;
|
||||
public boolean DETECT_NESTED_COPIES = true;
|
||||
public boolean CHECK_NESTED_FOR_QUICK_MERGE = false;
|
||||
public boolean IGNORE_SPACES_IN_ANNOTATE = true;
|
||||
public boolean SHOW_MERGE_SOURCES_IN_ANNOTATE = true;
|
||||
public boolean FORCE_UPDATE = false;
|
||||
|
||||
private final Map<File, MergeRootInfo> myMergeRootInfos = new HashMap<File, MergeRootInfo>();
|
||||
private final Map<File, UpdateRootInfo> myUpdateRootInfos = new HashMap<File, UpdateRootInfo>();
|
||||
private final List<AnnotationListener> myAnnotationListeners;
|
||||
private SvnInteractiveAuthenticationProvider myInteractiveProvider;
|
||||
|
||||
@Override
|
||||
public Element getState() {
|
||||
Element element = new Element("state");
|
||||
try {
|
||||
writeExternal(element);
|
||||
}
|
||||
catch (WriteExternalException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(Element state) {
|
||||
try {
|
||||
readExternal(state);
|
||||
}
|
||||
catch (InvalidDataException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SvnConfiguration17 getInstance(final Project project) {
|
||||
return ServiceManager.getService(project, SvnConfiguration17.class);
|
||||
}
|
||||
|
||||
public SvnConfiguration17(final Project project) {
|
||||
myProject = project;
|
||||
myAnnotationListeners = new ArrayList<AnnotationListener>();
|
||||
}
|
||||
|
||||
// accessed on AWT
|
||||
public void addAnnotationListener(final AnnotationListener listener) {
|
||||
myAnnotationListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeAnnotationListener(final AnnotationListener listener) {
|
||||
myAnnotationListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void setIgnoreSpacesInAnnotate(final boolean value) {
|
||||
final boolean changed = IGNORE_SPACES_IN_ANNOTATE != value;
|
||||
IGNORE_SPACES_IN_ANNOTATE = value;
|
||||
if (changed) {
|
||||
fireForAnnotationListeners();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireForAnnotationListeners() {
|
||||
final AnnotationListener[] listeners = myAnnotationListeners.toArray(new AnnotationListener[myAnnotationListeners.size()]);
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
final AnnotationListener listener = listeners[i];
|
||||
listener.onAnnotationChanged();
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
public class SvnSupportOptions {
|
||||
/**
|
||||
* version of "support SVN in IDEA". for features tracking. should grow
|
||||
*/
|
||||
private Long myVersion;
|
||||
|
||||
public SvnSupportOptions(final Long version) {
|
||||
myVersion = version;
|
||||
// will be set to SvnSupportOptions.CHANGELIST_SUPPORT after sync
|
||||
if (myVersion == null || myVersion.longValue() < SvnSupportOptions.CHANGELIST_SUPPORT) {
|
||||
myVersion = SvnSupportOptions.UPGRADE_TO_15_VERSION_ASKED;
|
||||
}
|
||||
}
|
||||
|
||||
private final static long UPGRADE_TO_15_VERSION_ASKED = 123;
|
||||
private final static long CHANGELIST_SUPPORT = 124;
|
||||
private final static long UPGRADE_TO_16_VERSION_ASKED = 125;
|
||||
|
||||
public boolean upgradeTo16Asked() {
|
||||
return (myVersion != null) && (UPGRADE_TO_16_VERSION_ASKED <= myVersion);
|
||||
}
|
||||
|
||||
public boolean changeListsSynchronized() {
|
||||
return (myVersion != null) && (CHANGELIST_SUPPORT <= myVersion);
|
||||
}
|
||||
|
||||
public void upgrade() {
|
||||
myVersion = UPGRADE_TO_16_VERSION_ASKED;
|
||||
}
|
||||
}
|
||||
|
||||
public SvnSupportOptions getSupportOptions() {
|
||||
if (mySupportOptions == null) {
|
||||
// used to be kept in SvnBranchConfigurationManager
|
||||
mySupportOptions = new SvnSupportOptions(SvnBranchConfigurationManager17.getInstance(myProject).getSupportValue());
|
||||
}
|
||||
return mySupportOptions;
|
||||
}
|
||||
|
||||
public String getConfigurationDirectory() {
|
||||
if (myConfigurationDirectory == null || isUseDefaultConfiguation()) {
|
||||
myConfigurationDirectory = IdeaSubversionConfigurationDirectory.getPath();
|
||||
}
|
||||
return myConfigurationDirectory;
|
||||
}
|
||||
|
||||
public boolean isUseDefaultConfiguation() {
|
||||
return myIsUseDefaultConfiguration;
|
||||
}
|
||||
|
||||
public void setConfigurationDirectory(String path) {
|
||||
myConfigurationDirectory = path;
|
||||
File dir = path == null ? new File(IdeaSubversionConfigurationDirectory.getPath()) : new File(path);
|
||||
SVNConfigFile.createDefaultConfiguration(dir);
|
||||
|
||||
myOptions = null;
|
||||
myAuthManager = null;
|
||||
myPassiveAuthManager = null;
|
||||
myInteractiveManager = null;
|
||||
myInteractiveProvider = null;
|
||||
RUNTIME_AUTH_CACHE.clear();
|
||||
}
|
||||
|
||||
public void setUseDefaultConfiguation(boolean useDefault) {
|
||||
myIsUseDefaultConfiguration = useDefault;
|
||||
myOptions = null;
|
||||
myAuthManager = null;
|
||||
myPassiveAuthManager = null;
|
||||
myInteractiveManager = null;
|
||||
myInteractiveProvider = null;
|
||||
RUNTIME_AUTH_CACHE.clear();
|
||||
}
|
||||
|
||||
public ISVNOptions getOptions(Project project) {
|
||||
if (myOptions == null) {
|
||||
File path = new File(getConfigurationDirectory());
|
||||
myOptions = SVNWCUtil.createDefaultOptions(path.getAbsoluteFile(), true);
|
||||
}
|
||||
return myOptions;
|
||||
}
|
||||
|
||||
public SvnAuthenticationManager getAuthenticationManager(final SvnVcs17 svnVcs) {
|
||||
if (myAuthManager == null) {
|
||||
// reloaded when configuration directory changes
|
||||
myAuthManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
|
||||
getInteractiveManager(svnVcs);
|
||||
// to init
|
||||
myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs, myInteractiveProvider));
|
||||
myAuthManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
|
||||
}
|
||||
return myAuthManager;
|
||||
}
|
||||
|
||||
public SvnAuthenticationManager getPassiveAuthenticationManager() {
|
||||
if (myPassiveAuthManager == null) {
|
||||
myPassiveAuthManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
|
||||
myPassiveAuthManager.setAuthenticationProvider(new ISVNAuthenticationProvider() {
|
||||
@Override
|
||||
public SVNAuthentication requestClientAuthentication(String kind,
|
||||
SVNURL url,
|
||||
String realm,
|
||||
SVNErrorMessage errorMessage,
|
||||
SVNAuthentication previousAuth,
|
||||
boolean authMayBeStored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int acceptServerAuthentication(SVNURL url, String realm, Object certificate, boolean resultMayBeStored) {
|
||||
return REJECTED;
|
||||
}
|
||||
});
|
||||
myPassiveAuthManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
|
||||
}
|
||||
return myPassiveAuthManager;
|
||||
}
|
||||
|
||||
public SvnAuthenticationManager getInteractiveManager(final SvnVcs17 svnVcs) {
|
||||
if (myInteractiveManager == null) {
|
||||
myInteractiveManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
|
||||
myInteractiveManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
|
||||
myInteractiveProvider = new SvnInteractiveAuthenticationProvider(svnVcs, myInteractiveManager);
|
||||
myInteractiveManager.setAuthenticationProvider(myInteractiveProvider);
|
||||
}
|
||||
return myInteractiveManager;
|
||||
}
|
||||
|
||||
public void getServerFilesManagers(final Ref<SvnServerFileManager> systemManager, final Ref<SvnServerFileManager> userManager) {
|
||||
// created only if does not exist
|
||||
SVNConfigFile.createDefaultConfiguration(new File(getConfigurationDirectory()));
|
||||
|
||||
systemManager.set(new SvnServerFileManagerImpl(new IdeaSVNConfigFile(new File(SVNFileUtil.getSystemConfigurationDirectory(), SERVERS_FILE_NAME))));
|
||||
userManager.set(new SvnServerFileManagerImpl(new IdeaSVNConfigFile(new File(getConfigurationDirectory(), SERVERS_FILE_NAME))));
|
||||
}
|
||||
|
||||
public String getUpgradeMode() {
|
||||
return myUpgradeMode;
|
||||
}
|
||||
|
||||
public void setUpgradeMode(String upgradeMode) {
|
||||
myUpgradeMode = upgradeMode;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public void readExternal(Element element) throws InvalidDataException {
|
||||
DefaultJDOMExternalizer.readExternal(this, element);
|
||||
List elems = element.getChildren("addpath");
|
||||
LOG.debug(elems.toString());
|
||||
ADD_PATHS = new String[elems.size()];
|
||||
for (int i = 0; i < elems.size(); i++) {
|
||||
Element elem = (Element)elems.get(i);
|
||||
ADD_PATHS[i] = elem.getAttributeValue("path");
|
||||
}
|
||||
Element configurationDirectory = element.getChild("configuration");
|
||||
if (configurationDirectory != null) {
|
||||
myConfigurationDirectory = configurationDirectory.getText();
|
||||
Attribute defaultAttr = configurationDirectory.getAttribute("useDefault");
|
||||
try {
|
||||
myIsUseDefaultConfiguration = defaultAttr != null && defaultAttr.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException e) {
|
||||
myIsUseDefaultConfiguration = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
myIsUseDefaultConfiguration = true;
|
||||
}
|
||||
// compatibility: this setting was moved from .iws to global settings
|
||||
List urls = element.getChildren("checkoutURL");
|
||||
for (Object url1 : urls) {
|
||||
Element child = (Element)url1;
|
||||
String url = child.getText();
|
||||
if (url != null) {
|
||||
SvnApplicationSettings17.getInstance().addCheckoutURL(url);
|
||||
}
|
||||
}
|
||||
myIsKeepLocks = element.getChild("keepLocks") != null;
|
||||
myRemoteStatus = element.getChild("remoteStatus") != null;
|
||||
myUpgradeMode = element.getChild("upgradeMode") != null ? element.getChild("upgradeMode").getText() : null;
|
||||
final Element useProxy = element.getChild("myIsUseDefaultProxy");
|
||||
if (useProxy == null) {
|
||||
myIsUseDefaultProxy = false;
|
||||
} else {
|
||||
myIsUseDefaultProxy = Boolean.parseBoolean(useProxy.getText());
|
||||
}
|
||||
final Element supportedVersion = element.getChild("supportedVersion");
|
||||
if (supportedVersion != null) {
|
||||
try {
|
||||
mySupportOptions = new SvnSupportOptions(Long.parseLong(supportedVersion.getText().trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
mySupportOptions = new SvnSupportOptions(null);
|
||||
}
|
||||
}
|
||||
final Attribute maxAnnotateRevisions = element.getAttribute("maxAnnotateRevisions");
|
||||
if (maxAnnotateRevisions != null) {
|
||||
try {
|
||||
myMaxAnnotateRevisions = maxAnnotateRevisions.getIntValue();
|
||||
}
|
||||
catch (DataConversionException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public void writeExternal(Element element) throws WriteExternalException {
|
||||
DefaultJDOMExternalizer.writeExternal(this, element);
|
||||
if (ADD_PATHS != null) {
|
||||
for (String aADD_PATHS : ADD_PATHS) {
|
||||
Element elem = new Element("addpath");
|
||||
elem.setAttribute("path", aADD_PATHS);
|
||||
element.addContent(elem);
|
||||
}
|
||||
}
|
||||
if (myConfigurationDirectory != null) {
|
||||
Element configurationDirectory = new Element("configuration");
|
||||
configurationDirectory.setText(myConfigurationDirectory);
|
||||
configurationDirectory.setAttribute("useDefault", myIsUseDefaultConfiguration ? "true" : "false");
|
||||
element.addContent(configurationDirectory);
|
||||
}
|
||||
if (myIsKeepLocks) {
|
||||
element.addContent(new Element("keepLocks"));
|
||||
}
|
||||
if (myRemoteStatus) {
|
||||
element.addContent(new Element("remoteStatus"));
|
||||
}
|
||||
if (myUpgradeMode != null) {
|
||||
element.addContent(new Element("upgradeMode").setText(myUpgradeMode));
|
||||
}
|
||||
element.addContent(new Element("myIsUseDefaultProxy").setText(myIsUseDefaultProxy ? "true" : "false"));
|
||||
if (mySupportOptions != null) {
|
||||
element.addContent(new Element("supportedVersion").setText("" + mySupportOptions.myVersion));
|
||||
}
|
||||
element.setAttribute("maxAnnotateRevisions", "" + myMaxAnnotateRevisions);
|
||||
}
|
||||
|
||||
public boolean isKeepLocks() {
|
||||
return myIsKeepLocks;
|
||||
}
|
||||
|
||||
public void setKeepLocks(boolean keepLocks) {
|
||||
myIsKeepLocks = keepLocks;
|
||||
}
|
||||
|
||||
public boolean isRemoteStatus() {
|
||||
return myRemoteStatus;
|
||||
}
|
||||
|
||||
public void setRemoteStatus(boolean remote) {
|
||||
myRemoteStatus = remote;
|
||||
}
|
||||
|
||||
public boolean isIsUseDefaultProxy() {
|
||||
return myIsUseDefaultProxy;
|
||||
}
|
||||
|
||||
public void setIsUseDefaultProxy(final boolean isUseDefaultProxy) {
|
||||
myIsUseDefaultProxy = isUseDefaultProxy;
|
||||
}
|
||||
|
||||
public static class AuthStorage implements ISVNAuthenticationStorage {
|
||||
|
||||
private final Map<String, Object> myStorage = new Hashtable<String, Object>();
|
||||
|
||||
public void clear() {
|
||||
myStorage.clear();
|
||||
}
|
||||
|
||||
public void putData(String kind, String realm, Object data) {
|
||||
if (data == null) {
|
||||
myStorage.remove(kind + "$" + realm);
|
||||
} else {
|
||||
myStorage.put(kind + "$" + realm, data);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getData(String kind, String realm) {
|
||||
return myStorage.get(kind + "$" + realm);
|
||||
}
|
||||
}
|
||||
|
||||
public MergeRootInfo getMergeRootInfo(final File file, final SvnVcs17 svnVcs) {
|
||||
if (!myMergeRootInfos.containsKey(file)) {
|
||||
myMergeRootInfos.put(file, new MergeRootInfo(file, svnVcs));
|
||||
}
|
||||
return myMergeRootInfos.get(file);
|
||||
}
|
||||
|
||||
public UpdateRootInfo getUpdateRootInfo(File file, final SvnVcs17 svnVcs) {
|
||||
if (!myUpdateRootInfos.containsKey(file)) {
|
||||
myUpdateRootInfos.put(file, new UpdateRootInfo(file, svnVcs));
|
||||
}
|
||||
return myUpdateRootInfos.get(file);
|
||||
}
|
||||
|
||||
public Map<File, UpdateRootInfo> getUpdateInfosMap() {
|
||||
return Collections.unmodifiableMap(myUpdateRootInfos);
|
||||
}
|
||||
|
||||
private static final List<String> ourAuthKinds = Arrays.asList(ISVNAuthenticationManager.PASSWORD, ISVNAuthenticationManager.SSH,
|
||||
ISVNAuthenticationManager.SSL, ISVNAuthenticationManager.USERNAME, "svn.ssl.server", "svn.ssh.server");
|
||||
|
||||
public void clearAuthenticationDirectory() {
|
||||
final File authDir = new File(getConfigurationDirectory(), "auth");
|
||||
if (authDir.exists()) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
public void run() {
|
||||
final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (ind != null) {
|
||||
ind.setIndeterminate(true);
|
||||
ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
|
||||
}
|
||||
final File[] files = authDir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return ourAuthKinds.contains(name);
|
||||
}
|
||||
});
|
||||
|
||||
for (File dir : files) {
|
||||
if (ind != null) {
|
||||
ind.setText("Deleting " + dir.getAbsolutePath());
|
||||
}
|
||||
FileUtil.delete(dir);
|
||||
}
|
||||
}
|
||||
}, "button.text.clear.authentication.cache", false, myProject);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean haveCredentialsFor(final String kind, final String realm) {
|
||||
return RUNTIME_AUTH_CACHE.getData(kind, realm) != null;
|
||||
}
|
||||
|
||||
public void acknowledge(final String kind, final String realm, final Object object) {
|
||||
RUNTIME_AUTH_CACHE.putData(kind, realm, object);
|
||||
}
|
||||
|
||||
public void clearCredentials(final String kind, final String realm) {
|
||||
RUNTIME_AUTH_CACHE.putData(kind, realm, null);
|
||||
}
|
||||
|
||||
public int getMaxAnnotateRevisions() {
|
||||
return myMaxAnnotateRevisions;
|
||||
}
|
||||
|
||||
public void setMaxAnnotateRevisions(int maxAnnotateRevisions) {
|
||||
myMaxAnnotateRevisions = maxAnnotateRevisions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Throwable2Computable;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
|
||||
import com.intellij.openapi.vcs.impl.CurrentRevisionProvider;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
class SvnContentRevision implements ContentRevision {
|
||||
private final SvnVcs17 myVcs;
|
||||
protected final FilePath myFile;
|
||||
private final SVNRevision myRevision;
|
||||
/**
|
||||
* this flag is necessary since SVN would not do remote request only if constant SVNRevision.BASE
|
||||
* -> usual current revision content class can't be used
|
||||
*/
|
||||
private final boolean myUseBaseRevision;
|
||||
|
||||
protected SvnContentRevision(SvnVcs17 vcs, @NotNull final FilePath file, final SVNRevision revision, final boolean useBaseRevision) {
|
||||
myVcs = vcs;
|
||||
myRevision = revision;
|
||||
myUseBaseRevision = useBaseRevision;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
public static SvnContentRevision createBaseRevision(@NotNull SvnVcs17 vcs, @NotNull final FilePath file, final SVNRevision revision) {
|
||||
if (file.getFileType().isBinary()) {
|
||||
return new SvnBinaryContentRevision(vcs, file, revision, true);
|
||||
}
|
||||
return new SvnContentRevision(vcs, file, revision, true);
|
||||
}
|
||||
|
||||
public static SvnContentRevision createRemote(@NotNull SvnVcs17 vcs, @NotNull final FilePath file, final SVNRevision revision) {
|
||||
if (file.getFileType().isBinary()) {
|
||||
return new SvnBinaryContentRevision(vcs, file, revision, false);
|
||||
}
|
||||
return new SvnContentRevision(vcs, file, revision, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getContent() throws VcsException {
|
||||
try {
|
||||
if (myUseBaseRevision) {
|
||||
return ContentRevisionCache.getOrLoadCurrentAsString(myVcs.getProject(), myFile, myVcs.getKeyInstanceMethod(),
|
||||
new CurrentRevisionProvider() {
|
||||
@Override
|
||||
public VcsRevisionNumber getCurrentRevision() throws VcsException {
|
||||
return getRevisionNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<VcsRevisionNumber, byte[]> get()
|
||||
throws VcsException, IOException {
|
||||
return new Pair<VcsRevisionNumber, byte[]>(getRevisionNumber(), getUpToDateBinaryContent());
|
||||
}
|
||||
}).getSecond();
|
||||
} else {
|
||||
return ContentRevisionCache.getOrLoadAsString(myVcs.getProject(), myFile, getRevisionNumber(), myVcs.getKeyInstanceMethod(),
|
||||
ContentRevisionCache.UniqueType.REPOSITORY_CONTENT,
|
||||
new Throwable2Computable<byte[], VcsException, IOException>() {
|
||||
@Override
|
||||
public byte[] compute() throws VcsException, IOException {
|
||||
return getUpToDateBinaryContent();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] getUpToDateBinaryContent() throws VcsException {
|
||||
File file = myFile.getIOFile();
|
||||
File lock = new File(file.getParentFile(), SvnUtil.PATH_TO_LOCK_FILE);
|
||||
if (lock.exists()) {
|
||||
throw new VcsException("Can not access file base revision contents: administrative area is locked");
|
||||
}
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
SVNWCClient wcClient = myVcs.createWCClient();
|
||||
try {
|
||||
wcClient.doGetFileContents(file, SVNRevision.UNDEFINED, myUseBaseRevision ? SVNRevision.BASE : myRevision, true, buffer);
|
||||
buffer.close();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FilePath getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VcsRevisionNumber getRevisionNumber() {
|
||||
return new SvnRevisionNumber(myRevision);
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return myFile.getPath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.RequestsMerger;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
|
||||
public class SvnCopiesRefreshManager {
|
||||
private final CopiesRefresh myCopiesRefresh;
|
||||
|
||||
public SvnCopiesRefreshManager(final Project project, final SvnFileUrlMappingImpl17 mapping) {
|
||||
myCopiesRefresh = new MyVeryRefresh();
|
||||
|
||||
final Runnable refresher = new MyRefresher(mapping);
|
||||
|
||||
final RequestsMerger requestsMerger = new RequestsMerger(refresher, new Consumer<Runnable>() {
|
||||
public void consume(final Runnable runnable) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(runnable);
|
||||
}
|
||||
});
|
||||
((MyVeryRefresh) myCopiesRefresh).setRequestMerger(requestsMerger);
|
||||
}
|
||||
|
||||
public CopiesRefresh getCopiesRefresh() {
|
||||
return myCopiesRefresh;
|
||||
}
|
||||
|
||||
private class MyVeryRefresh implements CopiesRefresh {
|
||||
private static final long ourQueryInterval = 1000;
|
||||
private RequestsMerger myRequestMerger;
|
||||
private final ProgressManager myPm;
|
||||
|
||||
private MyVeryRefresh() {
|
||||
myPm = ProgressManager.getInstance();
|
||||
}
|
||||
|
||||
public void setRequestMerger(RequestsMerger requestMerger) {
|
||||
myRequestMerger = requestMerger;
|
||||
}
|
||||
|
||||
public void ensureInit() {
|
||||
synchRequest(myPm.getProgressIndicator(), true);
|
||||
}
|
||||
|
||||
public void asynchRequest() {
|
||||
myRequestMerger.request();
|
||||
}
|
||||
|
||||
public void synchRequest() {
|
||||
synchRequest(myPm.getProgressIndicator(), false);
|
||||
}
|
||||
|
||||
private void synchRequest(final ProgressIndicator pi, final boolean isOnlyInit) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
final Runnable waiter = new Runnable() {
|
||||
public void run() {
|
||||
semaphore.up();
|
||||
}
|
||||
};
|
||||
semaphore.down();
|
||||
if (isOnlyInit) {
|
||||
myRequestMerger.ensureInitialization(waiter);
|
||||
} else {
|
||||
myRequestMerger.waitRefresh(waiter);
|
||||
}
|
||||
while (true) {
|
||||
if (semaphore.waitFor(ourQueryInterval)) break;
|
||||
if (pi != null) {
|
||||
pi.checkCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyRefresher implements Runnable {
|
||||
private final SvnFileUrlMappingImpl17 myMapping;
|
||||
|
||||
private MyRefresher(final SvnFileUrlMappingImpl17 mapping) {
|
||||
myMapping = mapping;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
myMapping.realRefresh();
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public class SvnCopyRootSimple {
|
||||
public String myVcsRoot;
|
||||
public String myCopyRoot;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.actions.VcsContextFactory;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.diff.DiffMixin;
|
||||
import com.intellij.openapi.vcs.diff.DiffProvider;
|
||||
import com.intellij.openapi.vcs.diff.ItemLatestState;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionDescription;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionDescriptionImpl;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.idea.svn17.history.LatestExistentSearcher;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SvnDiffProvider implements DiffProvider, DiffMixin {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnDiffProvider");
|
||||
public static final String COMMIT_MESSAGE = "svn:log";
|
||||
private final SvnVcs17 myVcs;
|
||||
|
||||
public SvnDiffProvider(final SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
}
|
||||
|
||||
public VcsRevisionNumber getCurrentRevision(VirtualFile file) {
|
||||
final SVNStatusClient client = myVcs.createStatusClient();
|
||||
try {
|
||||
final SVNStatus svnStatus = client.doStatus(new File(file.getPresentableUrl()), false, false);
|
||||
if (svnStatus.getCommittedRevision().equals(SVNRevision.UNDEFINED) && svnStatus.isCopied()) {
|
||||
return new SvnRevisionNumber(svnStatus.getCopyFromRevision());
|
||||
}
|
||||
return new SvnRevisionNumber(svnStatus.getRevision());
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.debug(e); // most likely the file is unversioned
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VcsRevisionDescription getCurrentRevisionDescription(VirtualFile file) {
|
||||
File path = new File(file.getPresentableUrl());
|
||||
return getCurrentRevisionDescription(path);
|
||||
}
|
||||
|
||||
private VcsRevisionDescription getCurrentRevisionDescription(File path) {
|
||||
final SVNWCClient client = myVcs.createWCClient();
|
||||
try {
|
||||
final SVNInfo svnInfo = client.doInfo(path, SVNRevision.UNDEFINED);
|
||||
|
||||
if (svnInfo.getCommittedRevision().equals(SVNRevision.UNDEFINED) && ! svnInfo.getCopyFromRevision().equals(SVNRevision.UNDEFINED) &&
|
||||
svnInfo.getCopyFromURL() != null) {
|
||||
SVNURL copyUrl = svnInfo.getCopyFromURL();
|
||||
String localPath = myVcs.getSvnFileUrlMapping().getLocalPath(copyUrl.toString());
|
||||
if (localPath != null) {
|
||||
return getCurrentRevisionDescription(new File(localPath));
|
||||
}
|
||||
}
|
||||
final String message = getProperties(client, path);
|
||||
return new VcsRevisionDescriptionImpl(new SvnRevisionNumber(svnInfo.getCommittedRevision()), svnInfo.getCommittedDate(),
|
||||
svnInfo.getAuthor(), message);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.debug(e); // most likely the file is unversioned
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getProperties(SVNWCClient client, File path) throws SVNException {
|
||||
final String[] message = new String[1];
|
||||
client.doGetRevisionProperty(path, null, SVNRevision.BASE, new ISVNPropertyHandler() {
|
||||
@Override
|
||||
public void handleProperty(File path, SVNPropertyData property) throws SVNException {
|
||||
handle(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException {
|
||||
handle(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleProperty(long revision, SVNPropertyData property) throws SVNException {
|
||||
handle(property);
|
||||
}
|
||||
|
||||
private void handle(SVNPropertyData data) {
|
||||
if (COMMIT_MESSAGE.equals(data.getName())) {
|
||||
message[0] = data.getValue().getString();
|
||||
}
|
||||
}
|
||||
});
|
||||
return message[0];
|
||||
}
|
||||
|
||||
private static ItemLatestState defaultResult() {
|
||||
return createResult(SVNRevision.HEAD, true, true);
|
||||
}
|
||||
|
||||
private static ItemLatestState createResult(final SVNRevision revision, final boolean exists, boolean defaultHead) {
|
||||
return new ItemLatestState(new SvnRevisionNumber(revision), exists, defaultHead);
|
||||
}
|
||||
|
||||
public ItemLatestState getLastRevision(VirtualFile file) {
|
||||
return getLastRevision(new File(file.getPath()));
|
||||
}
|
||||
|
||||
public ContentRevision createFileContent(final VcsRevisionNumber revisionNumber, final VirtualFile selectedFile) {
|
||||
FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(selectedFile);
|
||||
final SVNRevision svnRevision = ((SvnRevisionNumber)revisionNumber).getRevision();
|
||||
|
||||
if (! SVNRevision.HEAD.equals(svnRevision)) {
|
||||
if (revisionNumber.equals(getCurrentRevision(selectedFile))) {
|
||||
return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision);
|
||||
}
|
||||
}
|
||||
// not clear why we need it, with remote check..
|
||||
final SVNStatusClient client = myVcs.createStatusClient();
|
||||
try {
|
||||
final SVNStatus svnStatus = client.doStatus(new File(selectedFile.getPresentableUrl()), false, false);
|
||||
if (svnRevision.equals(svnStatus.getRevision())) {
|
||||
return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision);
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.debug(e); // most likely the file is unversioned
|
||||
}
|
||||
return SvnContentRevision.createRemote(myVcs, filePath, svnRevision);
|
||||
}
|
||||
|
||||
public ItemLatestState getLastRevision(FilePath filePath) {
|
||||
return getLastRevision(filePath.getIOFile());
|
||||
}
|
||||
|
||||
public VcsRevisionNumber getLatestCommittedRevision(VirtualFile vcsRoot) {
|
||||
// todo
|
||||
return null;
|
||||
}
|
||||
|
||||
private ItemLatestState getLastRevision(final File file) {
|
||||
final SVNStatusClient client = myVcs.createStatusClient();
|
||||
try {
|
||||
final SVNStatus svnStatus = client.doStatus(file, true, false);
|
||||
if (svnStatus == null) {
|
||||
// IDEADEV-21785 (no idea why this can happen)
|
||||
LOG.info("No SVN status returned for " + file.getPath());
|
||||
return defaultResult();
|
||||
}
|
||||
final boolean exists = ! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteContentsStatus()) &&
|
||||
! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteNodeStatus());
|
||||
if (! exists) {
|
||||
// get really latest revision
|
||||
final LatestExistentSearcher searcher = new LatestExistentSearcher(myVcs, svnStatus.getURL());
|
||||
final long revision = searcher.getDeletionRevision();
|
||||
|
||||
return createResult(SVNRevision.create(revision), exists, false);
|
||||
}
|
||||
final SVNRevision remoteRevision = svnStatus.getRemoteRevision();
|
||||
if (remoteRevision != null) {
|
||||
return createResult(remoteRevision, exists, false);
|
||||
}
|
||||
return createResult(svnStatus.getRevision(), exists, false);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.debug(e); // most likely the file is unversioned
|
||||
return defaultResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.EditFileProvider;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNProperty;
|
||||
import org.tmatesoft.svn.core.wc.SVNPropertyData;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author alex
|
||||
*/
|
||||
public class SvnEditFileProvider implements EditFileProvider {
|
||||
private final SvnVcs17 myVCS;
|
||||
|
||||
public SvnEditFileProvider(SvnVcs17 vcs) {
|
||||
myVCS = vcs;
|
||||
}
|
||||
|
||||
public void editFiles(VirtualFile[] files) throws VcsException {
|
||||
File[] ioFiles = new File[files.length];
|
||||
SVNWCClient client = myVCS.createWCClient();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
ioFiles[i] = new File(files[i].getPath());
|
||||
try {
|
||||
SVNPropertyData property = client
|
||||
.doGetProperty(ioFiles[i], SVNProperty.NEEDS_LOCK, SVNRevision.WORKING, SVNRevision.WORKING);
|
||||
if (property == null || property.getValue() == null) {
|
||||
throw new VcsException(SvnBundle.message("exception.text.file.miss.svn", ioFiles[i].getName()));
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
}
|
||||
SvnUtil.doLockFiles(myVCS.getProject(), myVCS, ioFiles);
|
||||
}
|
||||
|
||||
public String getRequestText() {
|
||||
return SvnBundle.message("confirmation.text.edit.file");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileAdapter;
|
||||
import com.intellij.openapi.vfs.VirtualFileEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SvnEntriesFileListener extends VirtualFileAdapter {
|
||||
private final Project myProject;
|
||||
private final Collection<SvnEntriesListener> myListeners = new ArrayList<SvnEntriesListener>();
|
||||
private final ProjectLevelVcsManager myVcsManager;
|
||||
|
||||
public SvnEntriesFileListener(final Project project) {
|
||||
myProject = project;
|
||||
myVcsManager = ProjectLevelVcsManager.getInstance(myProject);
|
||||
}
|
||||
|
||||
public void fileCreated(VirtualFileEvent event) {
|
||||
if (! event.isFromRefresh()) {
|
||||
return;
|
||||
}
|
||||
final VirtualFile file = event.getFile();
|
||||
|
||||
if (SvnUtil.SVN_ADMIN_DIR_NAME.equals(file.getName())) {
|
||||
if (event.getParent() != null) {
|
||||
VirtualFile parent = event.getParent();
|
||||
fireFileStatusesChanged(parent);
|
||||
fileEntriesChanged(parent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final AbstractVcs vcsFor = myVcsManager.getVcsFor(file);
|
||||
if (vcsFor == null) return;
|
||||
if (SvnVcs17.VCS_NAME.equals(vcsFor.getName())) {
|
||||
final RootUrlInfo path = ((SvnVcs17)vcsFor).getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath()));
|
||||
if (path != null && WorkingCopyFormat.ONE_DOT_SEVEN.equals(path.getFormat())) {
|
||||
VcsDirtyScopeManager.getInstance(myProject).filesDirty(Collections.singletonList(file), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void contentsChanged(VirtualFileEvent event) {
|
||||
if (! event.isFromRefresh()) {
|
||||
return;
|
||||
}
|
||||
final VirtualFile file = event.getFile();
|
||||
if (isEntriesFile(file) && file.getParent() != null) {
|
||||
VirtualFile parent = file.getParent();
|
||||
if (parent != null) {
|
||||
VirtualFile grandParent = parent.getParent();
|
||||
if (grandParent != null) {
|
||||
fireFileStatusesChanged(grandParent);
|
||||
fileEntriesChanged(grandParent);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final AbstractVcs vcsFor = myVcsManager.getVcsFor(file);
|
||||
if (vcsFor == null) return;
|
||||
if (SvnVcs17.VCS_NAME.equals(vcsFor.getName())) {
|
||||
final RootUrlInfo path = ((SvnVcs17)vcsFor).getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath()));
|
||||
if (path != null && WorkingCopyFormat.ONE_DOT_SEVEN.equals(path.getFormat())) {
|
||||
VcsDirtyScopeManager.getInstance(myProject).filesDirty(Collections.singletonList(file), null);
|
||||
fileRevisionProbablyChanged(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void fileDeleted(VirtualFileEvent event) {
|
||||
if (!event.isFromRefresh()) {
|
||||
return;
|
||||
}
|
||||
final VirtualFile file = event.getFile();
|
||||
if (SvnUtil.SVN_ADMIN_DIR_NAME.equals(file.getName())) {
|
||||
if (event.getParent() != null) {
|
||||
VirtualFile parent = event.getParent();
|
||||
fireFileStatusesChanged(parent);
|
||||
fileEntriesChanged(parent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getParent() != null) {
|
||||
final VirtualFile parent = event.getParent();
|
||||
final AbstractVcs vcsFor = myVcsManager.getVcsFor(parent);
|
||||
if (vcsFor == null) return;
|
||||
if (SvnVcs17.VCS_NAME.equals(vcsFor.getName())) {
|
||||
final RootUrlInfo path = ((SvnVcs17)vcsFor).getSvnFileUrlMapping().getWcRootForFilePath(new File(parent.getPath()));
|
||||
if (path != null && WorkingCopyFormat.ONE_DOT_SEVEN.equals(path.getFormat())) {
|
||||
VcsDirtyScopeManager.getInstance(myProject).filePathsDirty(
|
||||
Collections.<FilePath>singletonList(new FilePathImpl(new File(file.getPath()), file.isDirectory())), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fileRevisionProbablyChanged(final VirtualFile file) {
|
||||
final SvnEntriesListener[] listeners = myListeners.toArray(new SvnEntriesListener[myListeners.size()]);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (SvnEntriesListener listener : listeners) {
|
||||
listener.fileVersionProbablyChanged(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fileEntriesChanged(final VirtualFile parent) {
|
||||
final SvnEntriesListener[] listeners = myListeners.toArray(new SvnEntriesListener[myListeners.size()]);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (SvnEntriesListener listener : listeners) {
|
||||
listener.onEntriesChanged(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addListener(SvnEntriesListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(SvnEntriesListener listener) {
|
||||
myListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void fireFileStatusesChanged(VirtualFile parent) {
|
||||
final VirtualFile[] children = parent.getChildren();
|
||||
final List<VirtualFile> files = new ArrayList<VirtualFile>(children.length + 1);
|
||||
files.add(parent);
|
||||
Collections.addAll(files, children);
|
||||
VcsDirtyScopeManager.getInstance(myProject).filesDirty(files, null);
|
||||
/*
|
||||
final FileStatusManager fileStatusManager = FileStatusManager.getInstance(myProject);
|
||||
final VirtualFile[] children = parent.getChildren();
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
VirtualFile child = children[i];
|
||||
fileStatusManager.fileStatusChanged(child);
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MMODAL);
|
||||
*/
|
||||
}
|
||||
|
||||
private static boolean isEntriesFile(final VirtualFile file) {
|
||||
VirtualFile parent = file.getParent();
|
||||
return !file.isDirectory() && SvnUtil.ENTRIES_FILE_NAME.equals(file.getName()) && parent != null && SvnUtil.SVN_ADMIN_DIR_NAME.equals(parent.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
public interface SvnEntriesListener {
|
||||
void onEntriesChanged(VirtualFile directory);
|
||||
void fileVersionProbablyChanged(final VirtualFile file);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.FileStatusFactory;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class SvnFileStatus {
|
||||
private SvnFileStatus() {
|
||||
}
|
||||
|
||||
public static final FileStatus EXTERNAL =
|
||||
FileStatusFactory.SERVICE.getInstance()
|
||||
.createFileStatus("IDEA_SVN_FILESTATUS_EXTERNAL", SvnBundle.message("file.status.external"), new Color(0x72A038));
|
||||
|
||||
public static final FileStatus OBSTRUCTED =
|
||||
FileStatusFactory.SERVICE.getInstance()
|
||||
.createFileStatus("IDEA_SVN_FILESTATUS_OBSTRUCTED", SvnBundle.message("file.status.obstructed"), new Color(0x727238));
|
||||
|
||||
public static final FileStatus REPLACED =
|
||||
FileStatusFactory.SERVICE.getInstance().createFileStatus("IDEA_SVN_REPLACED",
|
||||
SvnBundle.message("file.status.replaced"),
|
||||
FileStatus.COLOR_ADDED);
|
||||
}
|
||||
@@ -0,0 +1,874 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandAdapter;
|
||||
import com.intellij.openapi.command.CommandEvent;
|
||||
import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.actions.VcsContextFactory;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vfs.LocalFileOperationsHandler;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshSession;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.vcsUtil.ActionWithTempFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNNodeKind;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class SvnFileSystemListener extends CommandAdapter implements LocalFileOperationsHandler {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFileSystemListener");
|
||||
private final LocalFileSystem myLfs;
|
||||
|
||||
private static class AddedFileInfo {
|
||||
private final VirtualFile myDir;
|
||||
private final String myName;
|
||||
@Nullable private final File myCopyFrom;
|
||||
private final boolean myRecursive;
|
||||
|
||||
public AddedFileInfo(final VirtualFile dir, final String name, @Nullable final File copyFrom, boolean recursive) {
|
||||
myDir = dir;
|
||||
myName = name;
|
||||
myCopyFrom = copyFrom;
|
||||
myRecursive = recursive;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MovedFileInfo {
|
||||
private final Project myProject;
|
||||
private final File mySrc;
|
||||
private final File myDst;
|
||||
|
||||
private MovedFileInfo(final Project project, final File src, final File dst) {
|
||||
myProject = project;
|
||||
mySrc = src;
|
||||
myDst = dst;
|
||||
}
|
||||
}
|
||||
|
||||
private final MultiMap<Project, AddedFileInfo> myAddedFiles = new MultiMap<Project, AddedFileInfo>();
|
||||
private final MultiMap<Project, File> myDeletedFiles = new MultiMap<Project, File>();
|
||||
private final List<MovedFileInfo> myMovedFiles = new ArrayList<MovedFileInfo>();
|
||||
private final Map<Project, List<VcsException>> myMoveExceptions = new HashMap<Project, List<VcsException>>();
|
||||
private final List<VirtualFile> myFilesToRefresh = new ArrayList<VirtualFile>();
|
||||
@Nullable private File myStorageForUndo;
|
||||
private final List<Pair<File, File>> myUndoStorageContents = new ArrayList<Pair<File, File>>();
|
||||
private boolean myUndoingMove = false;
|
||||
|
||||
public SvnFileSystemListener() {
|
||||
myLfs = LocalFileSystem.getInstance();
|
||||
}
|
||||
|
||||
private void addToMoveExceptions(final Project project, final SVNException e) {
|
||||
List<VcsException> exceptionList = myMoveExceptions.get(project);
|
||||
if (exceptionList == null) {
|
||||
exceptionList = new ArrayList<VcsException>();
|
||||
myMoveExceptions.put(project, exceptionList);
|
||||
}
|
||||
VcsException vcsException;
|
||||
if (SVNErrorCode.ENTRY_EXISTS.equals(e.getErrorMessage().getErrorCode())) {
|
||||
vcsException = new VcsException(Arrays.asList("Target of move operation is already under version control.",
|
||||
"Subversion move had not been performed. ", e.getMessage()));
|
||||
} else {
|
||||
vcsException = new VcsException(e);
|
||||
}
|
||||
exceptionList.add(vcsException);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public File copy(final VirtualFile file, final VirtualFile toDir, final String copyName) throws IOException {
|
||||
SvnVcs17 vcs = getVCS(toDir);
|
||||
if (vcs == null) {
|
||||
vcs = getVCS(file);
|
||||
}
|
||||
if (vcs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File srcFile = new File(file.getPath());
|
||||
File destFile = new File(new File(toDir.getPath()), copyName);
|
||||
final boolean dstDirUnderControl = SvnUtil.isSvnVersioned(destFile.getParentFile());
|
||||
if (! dstDirUnderControl && !isPendingAdd(vcs.getProject(), toDir)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! SvnUtil.isSvnVersioned(srcFile.getParentFile())) {
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(toDir, copyName, null, false));
|
||||
return null;
|
||||
}
|
||||
|
||||
final SVNStatus fileStatus = getFileStatus(vcs, srcFile);
|
||||
if (fileStatus != null && SvnVcs17.svnStatusIs(fileStatus, SVNStatusType.STATUS_ADDED)) {
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(toDir, copyName, null, false));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sameRoot(vcs, file.getParent(), toDir)) {
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(toDir, copyName, srcFile, false));
|
||||
return null;
|
||||
}
|
||||
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(toDir, copyName, null, false));
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean sameRoot(final SvnVcs17 vcs, final VirtualFile srcDir, final VirtualFile dstDir) {
|
||||
final UUIDHelper helper = new UUIDHelper(vcs);
|
||||
final String srcUUID = helper.getRepositoryUUID(vcs.getProject(), srcDir);
|
||||
final String dstUUID = helper.getRepositoryUUID(vcs.getProject(), dstDir);
|
||||
|
||||
return srcUUID != null && dstUUID != null && srcUUID.equals(dstUUID);
|
||||
}
|
||||
|
||||
private class UUIDHelper {
|
||||
private final SVNWCClient myWcClient;
|
||||
|
||||
private UUIDHelper(final SvnVcs17 vcs) {
|
||||
myWcClient = vcs.createWCClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* passed dir must be under VC control (it is assumed)
|
||||
*/
|
||||
@Nullable
|
||||
public String getRepositoryUUID(final Project project, final VirtualFile dir) {
|
||||
try {
|
||||
final SVNInfo info1 = myWcClient.doInfo(new File(dir.getPath()), SVNRevision.UNDEFINED);
|
||||
if (info1 == null || info1.getRepositoryUUID() == null) {
|
||||
// go deeper if current parent was added (if parent was added, it theoretically could NOT know its repo UUID)
|
||||
final VirtualFile parent = dir.getParent();
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
if (isPendingAdd(project, parent)) {
|
||||
return getRepositoryUUID(project, parent);
|
||||
}
|
||||
} else {
|
||||
return info1.getRepositoryUUID();
|
||||
}
|
||||
} catch (SVNException e) {
|
||||
// go to return default
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean move(VirtualFile file, VirtualFile toDir) throws IOException {
|
||||
File srcFile = getIOFile(file);
|
||||
File dstFile = new File(getIOFile(toDir), file.getName());
|
||||
|
||||
final SvnVcs17 vcs = getVCS(toDir);
|
||||
final SvnVcs17 sourceVcs = getVCS(file);
|
||||
if (vcs == null && sourceVcs == null) return false;
|
||||
|
||||
if (vcs == null) {
|
||||
return false;
|
||||
}
|
||||
if (sourceVcs == null) {
|
||||
return createItem(toDir, file.getName(), file.isDirectory(), true);
|
||||
}
|
||||
|
||||
if (isPendingAdd(vcs.getProject(), toDir)) {
|
||||
myMovedFiles.add(new MovedFileInfo(sourceVcs.getProject(), srcFile, dstFile));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
final VirtualFile oldParent = file.getParent();
|
||||
myFilesToRefresh.add(oldParent);
|
||||
myFilesToRefresh.add(toDir);
|
||||
return doMove(sourceVcs, srcFile, dstFile);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean rename(VirtualFile file, String newName) throws IOException {
|
||||
File srcFile = getIOFile(file);
|
||||
File dstFile = new File(srcFile.getParentFile(), newName);
|
||||
SvnVcs17 vcs = getVCS(file);
|
||||
if (vcs != null) {
|
||||
myFilesToRefresh.add(file.getParent());
|
||||
return doMove(vcs, srcFile, dstFile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean doMove(@NotNull SvnVcs17 vcs, final File src, final File dst) {
|
||||
long srcTime = src.lastModified();
|
||||
try {
|
||||
final boolean isUndo = isUndo(vcs);
|
||||
final String list = isUndo ? null : SvnChangelistListener.getCurrentMapping(vcs.getProject(), src);
|
||||
|
||||
final boolean is17 = SvnUtil.is17CopyPart(src);
|
||||
if (is17) {
|
||||
if (for17move(vcs, src, dst, isUndo)) return false;
|
||||
} else {
|
||||
if (for16move(vcs, src, dst, isUndo)) return false;
|
||||
}
|
||||
|
||||
if (! isUndo && list != null) {
|
||||
SvnChangelistListener.putUnderList(vcs.getProject(), list, dst);
|
||||
}
|
||||
dst.setLastModified(srcTime);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
addToMoveExceptions(vcs.getProject(), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean for17move(SvnVcs17 vcs, File src, File dst, boolean undo) throws SVNException {
|
||||
if (undo) {
|
||||
final SVNWCClient wcClient = vcs.createWCClient();
|
||||
myUndoingMove = true;
|
||||
wcClient.doRevert(dst, true);
|
||||
wcClient.doRevert(src, true);
|
||||
restoreFromUndoStorage(dst);
|
||||
} else {
|
||||
if (doUsualMove(vcs, src)) return true;
|
||||
final SVNCopyClient copyClient = vcs.createCopyClient();
|
||||
final SVNCopySource svnCopySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.BASE, src);
|
||||
copyClient.doCopy(new SVNCopySource[]{svnCopySource}, dst, true, false, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean doUsualMove(SvnVcs17 vcs, File src) {
|
||||
// if src is not under version control, do usual move.
|
||||
SVNStatus srcStatus = getFileStatus(vcs, src);
|
||||
if (srcStatus == null || SvnVcs17.svnStatusIsUnversioned(srcStatus) ||
|
||||
SvnVcs17.svnStatusIs(srcStatus, SVNStatusType.STATUS_OBSTRUCTED) ||
|
||||
SvnVcs17.svnStatusIs(srcStatus, SVNStatusType.STATUS_MISSING) ||
|
||||
SvnVcs17.svnStatusIs(srcStatus, SVNStatusType.STATUS_EXTERNAL)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean for16move(SvnVcs17 vcs, File src, File dst, boolean undo) throws SVNException {
|
||||
SVNMoveClient mover = vcs.createMoveClient();
|
||||
if (undo) {
|
||||
myUndoingMove = true;
|
||||
restoreFromUndoStorage(dst);
|
||||
mover.undoMove(src, dst);
|
||||
}
|
||||
else {
|
||||
// if src is not under version control, do usual move.
|
||||
if (doUsualMove(vcs, src)) return true;
|
||||
mover.doMove(src, dst);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void restoreFromUndoStorage(final File dst) {
|
||||
String normPath = FileUtil.toSystemIndependentName(dst.getPath());
|
||||
for (Iterator<Pair<File, File>> it = myUndoStorageContents.iterator(); it.hasNext();) {
|
||||
Pair<File, File> e = it.next();
|
||||
final String p = FileUtil.toSystemIndependentName(e.first.getPath());
|
||||
if (p.startsWith(normPath)) {
|
||||
try {
|
||||
FileUtil.rename(e.second, e.first);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
LOG.error(ex);
|
||||
FileUtil.asyncDelete(e.second);
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
if (myStorageForUndo != null) {
|
||||
final File[] files = myStorageForUndo.listFiles();
|
||||
if (files == null || files.length == 0) {
|
||||
FileUtil.asyncDelete(myStorageForUndo);
|
||||
myStorageForUndo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean createFile(VirtualFile dir, String name) throws IOException {
|
||||
return createItem(dir, name, false, false);
|
||||
}
|
||||
|
||||
public boolean createDirectory(VirtualFile dir, String name) throws IOException {
|
||||
return createItem(dir, name, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete file or directory (both 'undo' and 'do' modes)
|
||||
* unversioned: do nothing, return false
|
||||
* obstructed: do nothing, return false
|
||||
* external or wc root: do nothing, return false
|
||||
* missing: do nothing, return false
|
||||
* <p/>
|
||||
* versioned: schedule for deletion, return true
|
||||
* added: schedule for deletion (make unversioned), return true
|
||||
* copied, but not scheduled: schedule for deletion, return true
|
||||
* replaced: schedule for deletion, return true
|
||||
* <p/>
|
||||
* deleted: do nothing, return true (strange)
|
||||
*/
|
||||
public boolean delete(VirtualFile file) throws IOException {
|
||||
SvnVcs17 vcs = getVCS(file);
|
||||
if (vcs != null && SvnUtil.isAdminDirectory(file)) {
|
||||
return true;
|
||||
}
|
||||
File ioFile = getIOFile(file);
|
||||
if (! SvnUtil.isSvnVersioned(ioFile.getParentFile())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (SVNWCUtil.isWorkingCopyRoot(ioFile)) {
|
||||
return false;
|
||||
}
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
|
||||
SVNStatus status = getFileStatus(ioFile);
|
||||
|
||||
if (status == null ||
|
||||
SvnVcs17.svnStatusIsUnversioned(status) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_OBSTRUCTED) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_MISSING) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_EXTERNAL) ||
|
||||
SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_IGNORED)) {
|
||||
return false;
|
||||
} else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
if (isUndo(vcs)) {
|
||||
moveToUndoStorage(file);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (vcs != null) {
|
||||
if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_ADDED)) {
|
||||
try {
|
||||
final SVNWCClient wcClient = vcs.createWCClient();
|
||||
wcClient.doRevert(ioFile, false);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
else {
|
||||
myDeletedFiles.putValue(vcs.getProject(), ioFile);
|
||||
// packages deleted from disk should not be deleted from svn (IDEADEV-16066)
|
||||
if (file.isDirectory() || isUndo(vcs)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToUndoStorage(final VirtualFile file) {
|
||||
if (myStorageForUndo == null) {
|
||||
try {
|
||||
myStorageForUndo = FileUtil.createTempDirectory("svnUndoStorage", "");
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
final File tmpFile = FileUtil.findSequentNonexistentFile(myStorageForUndo, "tmp", "");
|
||||
myUndoStorageContents.add(0, new Pair<File, File>(new File(file.getPath()), tmpFile));
|
||||
new File(file.getPath()).renameTo(tmpFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* add file or directory:
|
||||
* <p/>
|
||||
* parent directory is:
|
||||
* unversioned: do nothing, return false
|
||||
* versioned:
|
||||
* entry is:
|
||||
* null: create entry, schedule for addition
|
||||
* missing: do nothing, return false
|
||||
* deleted, 'do' mode: try to create entry and it schedule for addition if kind is the same, otherwise do nothing, return false.
|
||||
* deleted: 'undo' mode: try to revert non-recursively, if kind is the same, otherwise do nothing, return false.
|
||||
* anything else: return false.
|
||||
*/
|
||||
private boolean createItem(VirtualFile dir, String name, boolean directory, final boolean recursive) {
|
||||
SvnVcs17 vcs = getVCS(dir);
|
||||
if (vcs == null) {
|
||||
return false;
|
||||
}
|
||||
if (isUndo(vcs) && SvnUtil.isAdminDirectory(dir, name)) {
|
||||
return false;
|
||||
}
|
||||
File ioDir = getIOFile(dir);
|
||||
boolean pendingAdd = isPendingAdd(vcs.getProject(), dir);
|
||||
if (! SvnUtil.isSvnVersioned(ioDir) && ! pendingAdd) {
|
||||
return false;
|
||||
}
|
||||
SVNWCClient wcClient = vcs.createWCClient();
|
||||
File targetFile = new File(ioDir, name);
|
||||
SVNStatus status = getFileStatus(vcs, targetFile);
|
||||
|
||||
if (status == null || status.getContentsStatus() == SVNStatusType.STATUS_NONE ||
|
||||
status.getContentsStatus() == SVNStatusType.STATUS_UNVERSIONED) {
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(dir, name, null, recursive));
|
||||
return false;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_MISSING)) {
|
||||
return false;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
SVNNodeKind kind = status.getKind();
|
||||
// kind differs.
|
||||
if (directory && kind != SVNNodeKind.DIR || !directory && kind != SVNNodeKind.FILE) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (isUndo(vcs)) {
|
||||
wcClient.doRevert(targetFile, false);
|
||||
return true;
|
||||
}
|
||||
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(dir, name, null, recursive));
|
||||
return false;
|
||||
}
|
||||
catch (SVNException e) {
|
||||
SVNFileUtil.deleteAll(targetFile, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isPendingAdd(final Project project, final VirtualFile dir) {
|
||||
final Collection<AddedFileInfo> addedFileInfos = myAddedFiles.get(project);
|
||||
for(AddedFileInfo i: addedFileInfos) {
|
||||
if (i.myDir == dir.getParent() && i.myName.equals(dir.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void commandStarted(CommandEvent event) {
|
||||
myUndoingMove = false;
|
||||
final Project project = event.getProject();
|
||||
if (project == null) return;
|
||||
commandStarted(project);
|
||||
}
|
||||
|
||||
void commandStarted(final Project project) {
|
||||
myUndoingMove = false;
|
||||
myMoveExceptions.remove(project);
|
||||
}
|
||||
|
||||
public void commandFinished(CommandEvent event) {
|
||||
final Project project = event.getProject();
|
||||
if (project == null) return;
|
||||
commandFinished(project);
|
||||
}
|
||||
|
||||
void commandFinished(final Project project) {
|
||||
checkOverwrites(project);
|
||||
if (myAddedFiles.containsKey(project)) {
|
||||
processAddedFiles(project);
|
||||
}
|
||||
processMovedFiles(project);
|
||||
if (myDeletedFiles.containsKey(project)) {
|
||||
processDeletedFiles(project);
|
||||
}
|
||||
|
||||
final List<VcsException> exceptionList = myMoveExceptions.get(project);
|
||||
if (exceptionList != null && ! exceptionList.isEmpty()) {
|
||||
AbstractVcsHelper.getInstance(project).showErrors(exceptionList, SvnBundle.message("move.files.errors.title"));
|
||||
}
|
||||
|
||||
if (!myFilesToRefresh.isEmpty()) {
|
||||
refreshFiles(project);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOverwrites(final Project project) {
|
||||
final Collection<AddedFileInfo> addedFileInfos = myAddedFiles.get(project);
|
||||
final Collection<File> deletedFiles = myDeletedFiles.get(project);
|
||||
if (addedFileInfos.isEmpty() || deletedFiles.isEmpty()) return;
|
||||
final Iterator<AddedFileInfo> iterator = addedFileInfos.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AddedFileInfo addedFileInfo = iterator.next();
|
||||
final File ioFile = new File(addedFileInfo.myDir.getPath(), addedFileInfo.myName);
|
||||
if (deletedFiles.remove(ioFile)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshFiles(final Project project) {
|
||||
final List<VirtualFile> toRefreshFiles = new ArrayList<VirtualFile>();
|
||||
final List<VirtualFile> toRefreshDirs = new ArrayList<VirtualFile>();
|
||||
for (VirtualFile file : myFilesToRefresh) {
|
||||
if (file == null) continue;
|
||||
if (file.isDirectory()) {
|
||||
toRefreshDirs.add(file);
|
||||
} else {
|
||||
toRefreshFiles.add(file);
|
||||
}
|
||||
}
|
||||
// if refresh asynchronously, local changes would also be notified that they are dirty asynchronously,
|
||||
// and commit could be executed while not all changes are visible
|
||||
final RefreshSession session = RefreshQueue.getInstance().createSession(true, true, new Runnable() {
|
||||
public void run() {
|
||||
if (project.isDisposed()) return;
|
||||
filterOutInvalid(toRefreshFiles);
|
||||
filterOutInvalid(toRefreshDirs);
|
||||
|
||||
final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
|
||||
vcsDirtyScopeManager.filesDirty(toRefreshFiles, toRefreshDirs);
|
||||
}
|
||||
});
|
||||
filterOutInvalid(myFilesToRefresh);
|
||||
session.addAllFiles(myFilesToRefresh);
|
||||
session.launch();
|
||||
myFilesToRefresh.clear();
|
||||
}
|
||||
|
||||
private static void filterOutInvalid(final Collection<VirtualFile> files) {
|
||||
for (Iterator<VirtualFile> iterator = files.iterator(); iterator.hasNext();) {
|
||||
final VirtualFile file = iterator.next();
|
||||
if (! file.isValid() || ! file.exists()) {
|
||||
LOG.info("Refresh root is not valid: " + file.getPath());
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processAddedFiles(Project project) {
|
||||
SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
List<VirtualFile> addedVFiles = new ArrayList<VirtualFile>();
|
||||
Map<VirtualFile, File> copyFromMap = new HashMap<VirtualFile, File>();
|
||||
final Set<VirtualFile> recursiveItems = new HashSet<VirtualFile>();
|
||||
fillAddedFiles(project, vcs, addedVFiles, copyFromMap, recursiveItems);
|
||||
if (addedVFiles.isEmpty()) return;
|
||||
final VcsShowConfirmationOption.Value value = vcs.getAddConfirmation().getValue();
|
||||
if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
|
||||
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
|
||||
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
|
||||
if (filesToProcess != null && !filesToProcess.isEmpty()) {
|
||||
final List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
runInBackground(project, "Adding files to Subversion",
|
||||
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
|
||||
if (!exceptions.isEmpty()) {
|
||||
vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runInBackground(final Project project, final String name, final Runnable runnable) {
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, name, false, project);
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable createAdditionRunnable(final Project project,
|
||||
final SvnVcs17 vcs,
|
||||
final Map<VirtualFile, File> copyFromMap,
|
||||
final Collection<VirtualFile> filesToProcess,
|
||||
final List<VcsException> exceptions) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SVNWCClient wcClient = vcs.createWCClient();
|
||||
final SVNCopyClient copyClient = vcs.createCopyClient();
|
||||
for(VirtualFile file: filesToProcess) {
|
||||
final File ioFile = new File(file.getPath());
|
||||
try {
|
||||
final File copyFrom = copyFromMap.get(file);
|
||||
if (copyFrom != null) {
|
||||
try {
|
||||
new ActionWithTempFile(ioFile) {
|
||||
protected void executeInternal() throws VcsException {
|
||||
try {
|
||||
// not recursive
|
||||
final SVNCopySource[] copySource = {new SVNCopySource(SVNRevision.WORKING, SVNRevision.WORKING, copyFrom)};
|
||||
copyClient.doCopy(copySource, ioFile, false, true, true);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new VcsException(e);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wcClient.doAdd(ioFile, true, false, false, true);
|
||||
}
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
exceptions.add(new VcsException(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Collection<VirtualFile> promptAboutAddition(SvnVcs17 vcs,
|
||||
List<VirtualFile> addedVFiles,
|
||||
VcsShowConfirmationOption.Value value,
|
||||
AbstractVcsHelper vcsHelper) {
|
||||
Collection<VirtualFile> filesToProcess;
|
||||
if (value == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
|
||||
filesToProcess = addedVFiles;
|
||||
}
|
||||
else {
|
||||
final String singleFilePrompt;
|
||||
if (addedVFiles.size() == 1 && addedVFiles.get(0).isDirectory()) {
|
||||
singleFilePrompt = SvnBundle.getString("confirmation.text.add.dir");
|
||||
}
|
||||
else {
|
||||
singleFilePrompt = SvnBundle.getString("confirmation.text.add.file");
|
||||
}
|
||||
filesToProcess = vcsHelper.selectFilesToProcess(addedVFiles, SvnBundle.message("confirmation.title.add.multiple.files"),
|
||||
null,
|
||||
SvnBundle.message("confirmation.title.add.file"), singleFilePrompt,
|
||||
vcs.getAddConfirmation());
|
||||
}
|
||||
return filesToProcess;
|
||||
}
|
||||
|
||||
private void fillAddedFiles(Project project,
|
||||
SvnVcs17 vcs,
|
||||
List<VirtualFile> addedVFiles,
|
||||
Map<VirtualFile, File> copyFromMap,
|
||||
Set<VirtualFile> recursiveItems) {
|
||||
final Collection<AddedFileInfo> addedFileInfos = myAddedFiles.remove(project);
|
||||
final ChangeListManager changeListManager = ChangeListManager.getInstance(project);
|
||||
|
||||
for (AddedFileInfo addedFileInfo : addedFileInfos) {
|
||||
final File ioFile = new File(getIOFile(addedFileInfo.myDir), addedFileInfo.myName);
|
||||
VirtualFile addedFile = addedFileInfo.myDir.findChild(addedFileInfo.myName);
|
||||
if (addedFile == null) {
|
||||
addedFile = myLfs.refreshAndFindFileByIoFile(ioFile);
|
||||
}
|
||||
if (addedFile != null) {
|
||||
final SVNStatus fileStatus = getFileStatus(vcs, ioFile);
|
||||
if (fileStatus == null || ! SvnVcs17.svnStatusIs(fileStatus, SVNStatusType.STATUS_IGNORED)) {
|
||||
boolean isIgnored = changeListManager.isIgnoredFile(addedFile);
|
||||
if (!isIgnored) {
|
||||
addedVFiles.add(addedFile);
|
||||
copyFromMap.put(addedFile, addedFileInfo.myCopyFrom);
|
||||
if (addedFileInfo.myRecursive) {
|
||||
recursiveItems.add(addedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDeletedFiles(Project project) {
|
||||
final List<FilePath> deletedFiles = new ArrayList<FilePath>();
|
||||
fillDeletedFiles(project, deletedFiles);
|
||||
if (deletedFiles.isEmpty() || myUndoingMove) return;
|
||||
SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
final VcsShowConfirmationOption.Value value = vcs.getDeleteConfirmation().getValue();
|
||||
if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
|
||||
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
|
||||
Collection<FilePath> filesToProcess;
|
||||
filesToProcess = promptAboutDeletion(deletedFiles, vcs, value, vcsHelper);
|
||||
if (filesToProcess != null && !filesToProcess.isEmpty()) {
|
||||
List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions));
|
||||
if (!exceptions.isEmpty()) {
|
||||
vcsHelper.showErrors(exceptions, SvnBundle.message("delete.files.errors.title"));
|
||||
}
|
||||
}
|
||||
for (FilePath file : deletedFiles) {
|
||||
final FilePath parent = file.getParentPath();
|
||||
if (parent != null) {
|
||||
myFilesToRefresh.add(parent.getVirtualFile());
|
||||
}
|
||||
}
|
||||
if (filesToProcess != null) {
|
||||
deletedFiles.removeAll(filesToProcess);
|
||||
}
|
||||
for (FilePath file : deletedFiles) {
|
||||
FileUtil.delete(file.getIOFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable createDeleteRunnable(final Project project,
|
||||
final SvnVcs17 vcs,
|
||||
final Collection<FilePath> filesToProcess,
|
||||
final List<VcsException> exceptions) {
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
SVNWCClient wcClient = vcs.createWCClient();
|
||||
for(FilePath file: filesToProcess) {
|
||||
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
|
||||
File ioFile = new File(file.getPath());
|
||||
try {
|
||||
wcClient.doDelete(ioFile, true, false);
|
||||
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
|
||||
vFile.refresh(true, true);
|
||||
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
|
||||
}
|
||||
else {
|
||||
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
exceptions.add(new VcsException(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Collection<FilePath> promptAboutDeletion(List<FilePath> deletedFiles,
|
||||
SvnVcs17 vcs,
|
||||
VcsShowConfirmationOption.Value value,
|
||||
AbstractVcsHelper vcsHelper) {
|
||||
Collection<FilePath> filesToProcess;
|
||||
if (value == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) {
|
||||
filesToProcess = new ArrayList<FilePath>(deletedFiles);
|
||||
}
|
||||
else {
|
||||
|
||||
final String singleFilePrompt;
|
||||
if (deletedFiles.size() == 1 && deletedFiles.get(0).isDirectory()) {
|
||||
singleFilePrompt = SvnBundle.getString("confirmation.text.delete.dir");
|
||||
}
|
||||
else {
|
||||
singleFilePrompt = SvnBundle.getString("confirmation.text.delete.file");
|
||||
}
|
||||
final Collection<FilePath> files = vcsHelper
|
||||
.selectFilePathsToProcess(deletedFiles, SvnBundle.message("confirmation.title.delete.multiple.files"), null,
|
||||
SvnBundle.message("confirmation.title.delete.file"), singleFilePrompt, vcs.getDeleteConfirmation());
|
||||
filesToProcess = files == null ? null : new ArrayList<FilePath>(files);
|
||||
}
|
||||
return filesToProcess;
|
||||
}
|
||||
|
||||
private void fillDeletedFiles(Project project, List<FilePath> deletedFiles) {
|
||||
final Collection<File> files = myDeletedFiles.remove(project);
|
||||
for (File file : files) {
|
||||
final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
|
||||
deletedFiles.add(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
private void processMovedFiles(final Project project) {
|
||||
if (myMovedFiles.isEmpty()) return;
|
||||
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext();) {
|
||||
MovedFileInfo movedFileInfo = iterator.next();
|
||||
if (movedFileInfo.myProject == project) {
|
||||
doMove(SvnVcs17.getInstance(project), movedFileInfo.mySrc, movedFileInfo.myDst);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
runInBackground(project, "Moving files in Subversion", runnable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SvnVcs17 getVCS(VirtualFile file) {
|
||||
Project[] projects = ProjectManager.getInstance().getOpenProjects();
|
||||
for (Project project : projects) {
|
||||
AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
|
||||
if (vcs instanceof SvnVcs17) {
|
||||
return (SvnVcs17)vcs;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static File getIOFile(VirtualFile vf) {
|
||||
return new File(vf.getPath()).getAbsoluteFile();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SVNStatus getFileStatus(File file) {
|
||||
final SVNClientManager clientManager = SVNClientManager.newInstance();
|
||||
try {
|
||||
SVNStatusClient stClient = clientManager.getStatusClient();
|
||||
return getFileStatus(file, stClient);
|
||||
}
|
||||
finally {
|
||||
clientManager.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SVNStatus getFileStatus(SvnVcs17 vcs, File file) {
|
||||
SVNStatusClient stClient = vcs.createStatusClient();
|
||||
return getFileStatus(file, stClient);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SVNStatus getFileStatus(final File file, final SVNStatusClient stClient) {
|
||||
try {
|
||||
return stClient.doStatus(file, false);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUndoOrRedo(@NotNull final Project project) {
|
||||
final UndoManager undoManager = UndoManager.getInstance(project);
|
||||
return undoManager.isUndoInProgress() || undoManager.isRedoInProgress();
|
||||
}
|
||||
|
||||
private static boolean isUndo(SvnVcs17 vcs) {
|
||||
if (vcs == null || vcs.getProject() == null) {
|
||||
return false;
|
||||
}
|
||||
Project p = vcs.getProject();
|
||||
return UndoManager.getInstance(p).isUndoInProgress();
|
||||
}
|
||||
|
||||
public void afterDone(final ThrowableConsumer<LocalFileOperationsHandler, IOException> invoker) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.command.CommandEvent;
|
||||
import com.intellij.openapi.command.CommandListener;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectLocator;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.LocalFileOperationsHandler;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SvnFileSystemListenerWrapper {
|
||||
private final LocalFileOperationsHandler myProxy;
|
||||
private final CommandListener myListener;
|
||||
|
||||
public SvnFileSystemListenerWrapper(final SvnFileSystemListener delegate) {
|
||||
final MyCommandListener listener = new MyCommandListener(delegate);
|
||||
myListener = listener;
|
||||
final MyStorage storage = new MyStorage(listener);
|
||||
myProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(),
|
||||
new Class<?>[]{LocalFileOperationsHandler.class}, new MyInvoker(storage, delegate));
|
||||
}
|
||||
|
||||
public void registerSelf() {
|
||||
LocalFileSystem.getInstance().registerAuxiliaryFileOperationsHandler(myProxy);
|
||||
CommandProcessor.getInstance().addCommandListener(myListener);
|
||||
}
|
||||
|
||||
public void unregisterSelf() {
|
||||
LocalFileSystem.getInstance().unregisterAuxiliaryFileOperationsHandler(myProxy);
|
||||
CommandProcessor.getInstance().removeCommandListener(myListener);
|
||||
}
|
||||
|
||||
private static class MyCommandListener implements CommandListener, MyMarker {
|
||||
private volatile boolean myInCommand;
|
||||
private final SvnFileSystemListener myDelegate;
|
||||
|
||||
public MyCommandListener(final SvnFileSystemListener delegate) {
|
||||
myDelegate = delegate;
|
||||
}
|
||||
|
||||
public void start(final Project project) {
|
||||
if (!myInCommand && project != null) {
|
||||
myDelegate.commandStarted(project);
|
||||
}
|
||||
}
|
||||
|
||||
public void finish(final Project project) {
|
||||
if (! myInCommand && project != null) {
|
||||
myDelegate.commandFinished(project);
|
||||
}
|
||||
}
|
||||
|
||||
public void commandStarted(CommandEvent event) {
|
||||
myInCommand = true;
|
||||
myDelegate.commandStarted(event);
|
||||
}
|
||||
|
||||
public void beforeCommandFinished(CommandEvent event) {
|
||||
myDelegate.beforeCommandFinished(event);
|
||||
}
|
||||
|
||||
public void commandFinished(CommandEvent event) {
|
||||
myInCommand = false;
|
||||
myDelegate.commandFinished(event);
|
||||
}
|
||||
|
||||
public void undoTransparentActionStarted() {
|
||||
myDelegate.undoTransparentActionStarted();
|
||||
}
|
||||
|
||||
public void undoTransparentActionFinished() {
|
||||
myDelegate.undoTransparentActionFinished();
|
||||
}
|
||||
}
|
||||
|
||||
private interface MyMarker {
|
||||
void start(final Project project);
|
||||
void finish(final Project project);
|
||||
}
|
||||
|
||||
private static class MyStorage implements InvocationHandler {
|
||||
private final MyMarker myMarker;
|
||||
private final Map<Project, Pair<String, Object[]>> myStarted;
|
||||
|
||||
private MyStorage(final MyMarker marker) {
|
||||
myMarker = marker;
|
||||
myStarted = new HashMap<Project, Pair<String, Object[]>>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Project getProject(Object[] args) {
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof VirtualFile) {
|
||||
return ProjectLocator.getInstance().guessProjectForFile((VirtualFile) arg);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
final Project project = getProject(args);
|
||||
if (project != null) {
|
||||
final Pair<String, Object[]> pair = myStarted.get(project);
|
||||
if (pair != null && method.getName().equals(pair.getFirst()) && Arrays.equals(args, pair.getSecond())) {
|
||||
myMarker.finish(project);
|
||||
}
|
||||
}
|
||||
//dont return null for auto unboxing to not face NPE
|
||||
return "boolean".equals(method.getReturnType().getName()) ? Boolean.TRUE : null;
|
||||
}
|
||||
|
||||
private void register(final Method method, final Object[] args) {
|
||||
final Object[] newArr = new Object[args.length];
|
||||
System.arraycopy(args, 0, newArr, 0, args.length);
|
||||
final Project project = getProject(args);
|
||||
if (project != null) {
|
||||
myMarker.start(project);
|
||||
myStarted.put(project, new Pair<String, Object[]>(method.getName(), newArr));
|
||||
Disposer.register(project, new Disposable() {
|
||||
public void dispose() {
|
||||
myStarted.remove(project);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyInvoker implements InvocationHandler {
|
||||
private final Object myDelegate;
|
||||
private final MyStorage myParent;
|
||||
private final LocalFileOperationsHandler myParentProxy;
|
||||
|
||||
private MyInvoker(final MyStorage parent, Object delegate) {
|
||||
myParent = parent;
|
||||
myDelegate = delegate;
|
||||
myParentProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(),
|
||||
new Class<?>[]{LocalFileOperationsHandler.class}, myParent);
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ("afterDone".equals(method.getName()) && args.length == 1) {
|
||||
((ThrowableConsumer<LocalFileOperationsHandler, IOException>)args[0]).consume(myParentProxy);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (LocalFileOperationsHandler.class.equals(method.getDeclaringClass())) {
|
||||
myParent.register(method, args);
|
||||
}
|
||||
if ("equals".equals(method.getName())) {
|
||||
return args[0].equals(this);
|
||||
}
|
||||
else if ("hashCode".equals(method.getName())) {
|
||||
return 1;
|
||||
}
|
||||
return method.invoke(myDelegate, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.AbstractVcs;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface SvnFileUrlMapping17 extends AbstractVcs.RootsConvertor {
|
||||
@Nullable
|
||||
SVNURL getUrlForFile(final File file);
|
||||
|
||||
@Nullable
|
||||
String getLocalPath(final String url);
|
||||
|
||||
@Nullable
|
||||
RootUrlInfo getWcRootForUrl(final String url);
|
||||
|
||||
List<RootUrlInfo> getAllWcInfos();
|
||||
|
||||
@Nullable
|
||||
RootUrlInfo getWcRootForFilePath(final File file);
|
||||
|
||||
/**
|
||||
* @return true if roots under SVN set by the user differs from real WC roots (are under specified roots)
|
||||
*/
|
||||
boolean rootsDiffer();
|
||||
|
||||
VirtualFile[] getNotFilteredRoots();
|
||||
|
||||
boolean isEmpty();
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbAwareRunnable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.ThreadLocalDefendedInvoker;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vcs.impl.VcsInitObject;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNURLUtil;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
@State(
|
||||
name = "SvnFileUrlMappingImpl17",
|
||||
storages = {
|
||||
@Storage(
|
||||
file = "$WORKSPACE_FILE$"
|
||||
)}
|
||||
)
|
||||
class SvnFileUrlMappingImpl17 implements SvnFileUrlMapping17, PersistentStateComponent<SvnMappingSavedPart>, ProjectComponent {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFileUrlMappingImpl17");
|
||||
|
||||
private final SvnCompatibilityChecker myChecker;
|
||||
private final Object myMonitor = new Object();
|
||||
// strictly: what real roots are under what vcs mappings
|
||||
private final SvnMapping myMapping;
|
||||
// grouped; if there are several mappings one under another, will return the upmost
|
||||
private final SvnMapping myMoreRealMapping;
|
||||
private final MyRootsHelper myHelper;
|
||||
private final Project myProject;
|
||||
private final NestedCopiesSink myTempSink;
|
||||
private boolean myInitialized;
|
||||
|
||||
private static class MyRootsHelper extends ThreadLocalDefendedInvoker<VirtualFile[]> {
|
||||
private final ProjectLevelVcsManager myPlVcsManager;
|
||||
|
||||
private MyRootsHelper(final ProjectLevelVcsManager vcsManager) {
|
||||
myPlVcsManager = vcsManager;
|
||||
}
|
||||
|
||||
protected VirtualFile[] execute(Project project) {
|
||||
return myPlVcsManager.getRootsUnderVcs(SvnVcs17.getInstance(project));
|
||||
}
|
||||
}
|
||||
|
||||
public static SvnFileUrlMappingImpl17 getInstance(final Project project) {
|
||||
return PeriodicalTasksCloser.getInstance().safeGetComponent(project, SvnFileUrlMappingImpl17.class);
|
||||
}
|
||||
|
||||
private SvnFileUrlMappingImpl17(final Project project, final ProjectLevelVcsManager vcsManager) {
|
||||
myProject = project;
|
||||
myMapping = new SvnMapping();
|
||||
myMoreRealMapping = new SvnMapping();
|
||||
myHelper = new MyRootsHelper(vcsManager);
|
||||
myChecker = new SvnCompatibilityChecker(project);
|
||||
myTempSink = new NestedCopiesSink();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SVNURL getUrlForFile(final File file) {
|
||||
final RootUrlInfo rootUrlInfo = getWcRootForFilePath(file);
|
||||
if (rootUrlInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String absolutePath = file.getAbsolutePath();
|
||||
final String rootAbsPath = rootUrlInfo.getIoFile().getAbsolutePath();
|
||||
if (absolutePath.length() < rootAbsPath.length()) {
|
||||
// remove last separator from etalon name
|
||||
if (absolutePath.equals(rootAbsPath.substring(0, rootAbsPath.length() - 1))) {
|
||||
return rootUrlInfo.getAbsoluteUrlAsUrl();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
final String relativePath = absolutePath.substring(rootAbsPath.length());
|
||||
try {
|
||||
return rootUrlInfo.getAbsoluteUrlAsUrl().appendPath(FileUtil.toSystemIndependentName(relativePath), true);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.info(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getLocalPath(final String url) {
|
||||
synchronized (myMonitor) {
|
||||
final String rootUrl = getUrlRootForUrl(url);
|
||||
if (rootUrl == null) {
|
||||
return null;
|
||||
}
|
||||
final RootUrlInfo parentInfo = myMapping.byUrl(rootUrl);
|
||||
if (parentInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileByUrl(parentInfo.getIoFile().getAbsolutePath(), rootUrl, url).getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
public static File fileByUrl(final String parentPath, final String parentUrl, final String childUrl) {
|
||||
return new File(parentPath, childUrl.substring(parentUrl.length()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RootUrlInfo getWcRootForFilePath(final File file) {
|
||||
synchronized (myMonitor) {
|
||||
final String root = getRootForPath(file);
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return myMapping.byFile(root);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean rootsDiffer() {
|
||||
synchronized (myMonitor) {
|
||||
return myMapping.isRootsDifferFromSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RootUrlInfo getWcRootForUrl(final String url) {
|
||||
synchronized (myMonitor) {
|
||||
final String rootUrl = getUrlRootForUrl(url);
|
||||
if (rootUrl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final RootUrlInfo result = myMapping.byUrl(rootUrl);
|
||||
if (result == null) {
|
||||
LOG.info("Inconsistent maps for url:" + url + " found root url: " + rootUrl);
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns real working copies roots - if there is <Project Root> -> Subversion setting,
|
||||
* and there is one working copy, will return one root
|
||||
*/
|
||||
public List<RootUrlInfo> getAllWcInfos() {
|
||||
synchronized (myMonitor) {
|
||||
// a copy is created inside
|
||||
return myMoreRealMapping.getAllCopies();
|
||||
}
|
||||
}
|
||||
|
||||
public List<VirtualFile> convertRoots(final List<VirtualFile> result) {
|
||||
if (ThreadLocalDefendedInvoker.isInside()) return result;
|
||||
|
||||
synchronized (myMonitor) {
|
||||
final List<VirtualFile> cachedRoots = myMapping.getUnderVcsRoots();
|
||||
final List<VirtualFile> lonelyRoots = myMapping.getLonelyRoots();
|
||||
if (! lonelyRoots.isEmpty()) {
|
||||
myChecker.reportNoRoots(lonelyRoots);
|
||||
}
|
||||
if (cachedRoots.isEmpty()) {
|
||||
// todo +-
|
||||
return result;
|
||||
}
|
||||
return cachedRoots;
|
||||
}
|
||||
}
|
||||
|
||||
public void acceptNestedData(final Set<NestedCopiesBuilder.MyPointInfo> set) {
|
||||
myTempSink.add(set);
|
||||
}
|
||||
|
||||
private boolean init() {
|
||||
synchronized (myMonitor) {
|
||||
final boolean result = myInitialized;
|
||||
myInitialized = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void realRefresh() {
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(myProject);
|
||||
final VirtualFile[] roots = myHelper.executeDefended(myProject);
|
||||
|
||||
final CopiesApplier copiesApplier = new CopiesApplier();
|
||||
final CopiesDetector copiesDetector = new CopiesDetector(vcs, copiesApplier, new Getter<NestedCopiesData>() {
|
||||
public NestedCopiesData get() {
|
||||
return myTempSink.receive();
|
||||
}
|
||||
});
|
||||
// do not send additional request for nested copies when in init state
|
||||
copiesDetector.detectCopyRoots(roots, init());
|
||||
}
|
||||
|
||||
private class CopiesApplier {
|
||||
public void apply(final SvnVcs17 vcs, final List<RootUrlInfo> roots, final List<VirtualFile> lonelyRoots) {
|
||||
final SvnMapping mapping = new SvnMapping();
|
||||
mapping.addAll(roots);
|
||||
mapping.reportLonelyRoots(lonelyRoots);
|
||||
|
||||
final SvnMapping groupedMapping = new SvnMapping();
|
||||
final List<RootUrlInfo> filtered = new ArrayList<RootUrlInfo>();
|
||||
ForNestedRootChecker.filterOutSuperfluousChildren(vcs, roots, filtered);
|
||||
|
||||
groupedMapping.addAll(filtered);
|
||||
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (myMonitor) {
|
||||
myMapping.copyFrom(mapping);
|
||||
myMoreRealMapping.copyFrom(groupedMapping);
|
||||
}
|
||||
}
|
||||
});
|
||||
myProject.getMessageBus().syncPublisher(SvnVcs17.ROOTS_RELOADED).run();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CopiesDetector {
|
||||
private final SvnVcs17 myVcs;
|
||||
private final CopiesApplier myApplier;
|
||||
private final List<VirtualFile> myLonelyRoots;
|
||||
private final List<RootUrlInfo> myTopRoots;
|
||||
private final RepositoryRoots myRepositoryRoots;
|
||||
private final Getter<NestedCopiesData> myGate;
|
||||
|
||||
private CopiesDetector(final SvnVcs17 vcs, final CopiesApplier applier, final Getter<NestedCopiesData> gate) {
|
||||
myVcs = vcs;
|
||||
myApplier = applier;
|
||||
myGate = gate;
|
||||
myTopRoots = new ArrayList<RootUrlInfo>();
|
||||
myLonelyRoots = new ArrayList<VirtualFile>();
|
||||
myRepositoryRoots = new RepositoryRoots(myVcs);
|
||||
}
|
||||
|
||||
public void detectCopyRoots(final VirtualFile[] roots, final boolean clearState) {
|
||||
final Getter<Boolean> cancelGetter = new Getter<Boolean>() {
|
||||
public Boolean get() {
|
||||
return myVcs.getProject().isDisposed();
|
||||
}
|
||||
};
|
||||
|
||||
for (final VirtualFile vcsRoot : roots) {
|
||||
final List<Real> foundRoots = ForNestedRootChecker.getAllNestedWorkingCopies(vcsRoot, myVcs, false, cancelGetter);
|
||||
if (foundRoots.isEmpty()) {
|
||||
myLonelyRoots.add(vcsRoot);
|
||||
}
|
||||
// filter out bad(?) items
|
||||
for (Real foundRoot : foundRoots) {
|
||||
final SVNURL repoRoot = foundRoot.getInfo().getRepositoryRootURL();
|
||||
if (repoRoot == null) {
|
||||
LOG.info("Error: cannot find repository URL for versioned folder: " + foundRoot.getFile().getPath());
|
||||
} else {
|
||||
myRepositoryRoots.register(repoRoot);
|
||||
myTopRoots.add(new RootUrlInfo(repoRoot, foundRoot.getInfo().getURL(),
|
||||
SvnFormatSelector.getWorkingCopyFormat(new File(foundRoot.getFile().getPath())), foundRoot.getFile(), vcsRoot));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! SvnConfiguration17.getInstance(myVcs.getProject()).DETECT_NESTED_COPIES) {
|
||||
myApplier.apply(myVcs, myTopRoots, myLonelyRoots);
|
||||
} else {
|
||||
addNestedRoots(clearState);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNestedRoots(final boolean clearState) {
|
||||
final List<VirtualFile> basicVfRoots = ObjectsConvertor.convert(myTopRoots, new Convertor<RootUrlInfo, VirtualFile>() {
|
||||
public VirtualFile convert(final RootUrlInfo real) {
|
||||
return real.getVirtualFile();
|
||||
}
|
||||
});
|
||||
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(myVcs.getProject());
|
||||
|
||||
if (clearState) {
|
||||
// clear what was reported before (could be for currently-not-existing roots)
|
||||
myGate.get();
|
||||
}
|
||||
clManager.invokeAfterUpdate(new Runnable() {
|
||||
public void run() {
|
||||
final List<RootUrlInfo> nestedRoots = new ArrayList<RootUrlInfo>();
|
||||
|
||||
final NestedCopiesData data = myGate.get();
|
||||
for (NestedCopiesBuilder.MyPointInfo info : data.getSet()) {
|
||||
if (NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType())) {
|
||||
final File infoFile = new File(info.getFile().getPath());
|
||||
boolean copyFound = false;
|
||||
for (RootUrlInfo topRoot : myTopRoots) {
|
||||
if (topRoot.getIoFile().equals(infoFile)) {
|
||||
topRoot.setType(info.getType());
|
||||
copyFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (copyFound) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
final SVNStatus svnStatus = SvnUtil.getStatus(myVcs, infoFile);
|
||||
if (svnStatus.getURL() == null) continue;
|
||||
info.setUrl(svnStatus.getURL());
|
||||
info.setFormat(WorkingCopyFormat.getInstance(svnStatus.getWorkingCopyFormat()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (RootUrlInfo topRoot : myTopRoots) {
|
||||
if (VfsUtil.isAncestor(topRoot.getVirtualFile(), info.getFile(), true)) {
|
||||
final SVNURL repoRoot = myRepositoryRoots.ask(info.getUrl());
|
||||
if (repoRoot != null) {
|
||||
final RootUrlInfo rootInfo = new RootUrlInfo(repoRoot, info.getUrl(), info.getFormat(), info.getFile(), topRoot.getRoot());
|
||||
rootInfo.setType(info.getType());
|
||||
nestedRoots.add(rootInfo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check those top roots which ARE externals, but that was not detected due to they itself were the status request target
|
||||
//new SvnNestedTypeRechecker(myVcs.getProject(), myTopRoots).run();
|
||||
|
||||
myTopRoots.addAll(nestedRoots);
|
||||
myApplier.apply(myVcs, myTopRoots, myLonelyRoots);
|
||||
}
|
||||
}, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, null, new Consumer<VcsDirtyScopeManager>() {
|
||||
public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) {
|
||||
if (clearState) {
|
||||
vcsDirtyScopeManager.filesDirty(null, basicVfRoots);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static SVNStatus getExternalItemStatus(final SvnVcs17 vcs, final File file) {
|
||||
final SVNStatusClient statusClient = vcs.createStatusClient();
|
||||
try {
|
||||
if (file.isDirectory()) {
|
||||
return statusClient.doStatus(file, false);
|
||||
} else {
|
||||
final File parent = file.getParentFile();
|
||||
if (parent != null) {
|
||||
statusClient.setFilesProvider(new ISVNStatusFileProvider() {
|
||||
public Map getChildrenFiles(File parent) {
|
||||
return Collections.singletonMap(file.getAbsolutePath(), file);
|
||||
}
|
||||
});
|
||||
final Ref<SVNStatus> refStatus = new Ref<SVNStatus>();
|
||||
statusClient.doStatus(parent, SVNRevision.WORKING, SVNDepth.FILES, false, true, false, false, new ISVNStatusHandler() {
|
||||
public void handleStatus(final SVNStatus status) throws SVNException {
|
||||
if (file.equals(status.getFile())) {
|
||||
refStatus.set(status);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
return refStatus.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class RepositoryRoots {
|
||||
private final SvnVcs17 myVcs;
|
||||
private final Set<SVNURL> myRoots;
|
||||
|
||||
private RepositoryRoots(final SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
myRoots = new HashSet<SVNURL>();
|
||||
}
|
||||
|
||||
public void register(final SVNURL url) {
|
||||
myRoots.add(url);
|
||||
}
|
||||
|
||||
public SVNURL ask(final SVNURL url) {
|
||||
for (SVNURL root : myRoots) {
|
||||
if (root.equals(SVNURLUtil.getCommonURLAncestor(root, url))) {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
final SVNURL newUrl = SvnUtil.getRepositoryRoot(myVcs, url);
|
||||
if (newUrl != null) {
|
||||
myRoots.add(newUrl);
|
||||
return newUrl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RepoInfo {
|
||||
private final SVNURL myUrl;
|
||||
private final boolean myRepoSupportsMergeinfo;
|
||||
|
||||
private RepoInfo(final SVNURL url, final boolean repoSupportsMergeinfo) {
|
||||
myRepoSupportsMergeinfo = repoSupportsMergeinfo;
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
public boolean isRepoSupportsMergeinfo() {
|
||||
return myRepoSupportsMergeinfo;
|
||||
}
|
||||
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUrlRootForUrl(final String currentUrl) {
|
||||
for (String url : myMapping.getUrls()) {
|
||||
if (SVNPathUtil.isAncestor(url, currentUrl)) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRootForPath(final File currentPath) {
|
||||
String convertedPath = currentPath.getAbsolutePath();
|
||||
convertedPath = (currentPath.isDirectory() && (! convertedPath.endsWith(File.separator))) ? convertedPath + File.separator :
|
||||
convertedPath;
|
||||
synchronized (myMonitor) {
|
||||
return myMapping.getRootForPath(convertedPath);
|
||||
}
|
||||
}
|
||||
|
||||
public VirtualFile[] getNotFilteredRoots() {
|
||||
return myHelper.executeDefended(myProject);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
synchronized (myMonitor) {
|
||||
return myMapping.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public SvnMappingSavedPart getState() {
|
||||
final SvnMappingSavedPart result = new SvnMappingSavedPart();
|
||||
|
||||
final SvnMapping mapping = new SvnMapping();
|
||||
final SvnMapping realMapping = new SvnMapping();
|
||||
synchronized (myMonitor) {
|
||||
mapping.copyFrom(myMapping);
|
||||
realMapping.copyFrom(myMoreRealMapping);
|
||||
}
|
||||
|
||||
for (RootUrlInfo info : mapping.getAllCopies()) {
|
||||
result.add(convert(info));
|
||||
}
|
||||
for (RootUrlInfo info : realMapping.getAllCopies()) {
|
||||
result.addReal(convert(info));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SvnCopyRootSimple convert(final RootUrlInfo info) {
|
||||
final SvnCopyRootSimple copy = new SvnCopyRootSimple();
|
||||
copy.myVcsRoot = FileUtil.toSystemDependentName(info.getRoot().getPath());
|
||||
copy.myCopyRoot = info.getIoFile().getAbsolutePath();
|
||||
return copy;
|
||||
}
|
||||
|
||||
public void loadState(final SvnMappingSavedPart state) {
|
||||
((ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject)).addInitializationRequest(
|
||||
VcsInitObject.AFTER_COMMON, new DumbAwareRunnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final SvnMapping mapping = new SvnMapping();
|
||||
final SvnMapping realMapping = new SvnMapping();
|
||||
try {
|
||||
fillMapping(mapping, state.getMappingRoots());
|
||||
fillMapping(realMapping, state.getMoreRealMappingRoots());
|
||||
} catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOG.info(t);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (myMonitor) {
|
||||
myMapping.copyFrom(mapping);
|
||||
myMoreRealMapping.copyFrom(realMapping);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fillMapping(final SvnMapping mapping, final List<SvnCopyRootSimple> list) {
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
|
||||
for (SvnCopyRootSimple simple : list) {
|
||||
final VirtualFile copyRoot = lfs.findFileByIoFile(new File(simple.myCopyRoot));
|
||||
final VirtualFile vcsRoot = lfs.findFileByIoFile(new File(simple.myVcsRoot));
|
||||
|
||||
if (copyRoot == null || vcsRoot == null) continue;
|
||||
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(myProject);
|
||||
final SVNInfo svnInfo = vcs.getInfo(copyRoot);
|
||||
if ((svnInfo == null) || (svnInfo.getRepositoryRootURL() == null)) continue;
|
||||
|
||||
final RootUrlInfo info = new RootUrlInfo(svnInfo.getRepositoryRootURL(), svnInfo.getURL(),
|
||||
SvnFormatSelector.getWorkingCopyFormat(svnInfo.getFile()), copyRoot, vcsRoot);
|
||||
mapping.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
public void projectOpened() {
|
||||
}
|
||||
|
||||
public void projectClosed() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getComponentName() {
|
||||
return "SvnFileUrlMappingImpl17";
|
||||
}
|
||||
|
||||
public void initComponent() {
|
||||
}
|
||||
|
||||
public void disposeComponent() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.util.WaitForProgressToShow;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.dialogs.UpgradeFormatDialog;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNErrorMessage;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.ISVNAdminAreaFactorySelector;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaFactory;
|
||||
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
|
||||
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class SvnFormatSelector implements ISVNAdminAreaFactorySelector {
|
||||
public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws SVNException {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return factories;
|
||||
}
|
||||
|
||||
if (! writeAccess) {
|
||||
return factories;
|
||||
}
|
||||
|
||||
final WorkingCopyFormat format = getWorkingCopyFormat(path);
|
||||
Collection result = format2Factories(format, factories);
|
||||
|
||||
if (result == null) {
|
||||
final WorkingCopyFormat presetFormat = SvnWorkingCopyFormatHolder.getPresetFormat();
|
||||
if (presetFormat != null) {
|
||||
result = format2Factories(presetFormat, factories);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Collection format2Factories(final WorkingCopyFormat format, final Collection factories) {
|
||||
if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) {
|
||||
return factories;
|
||||
} else if (WorkingCopyFormat.ONE_DOT_FIVE.equals(format)) {
|
||||
return factoriesFor15(factories);
|
||||
} else if (WorkingCopyFormat.ONE_DOT_FOUR.equals(format)) {
|
||||
return factoriesFor14(factories);
|
||||
} else if (WorkingCopyFormat.ONE_DOT_THREE.equals(format)) {
|
||||
return factoriesFor13(factories);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Collection<SVNAdminAreaFactory> factoriesFor13(final Collection factories) {
|
||||
for (Iterator iterator = factories.iterator(); iterator.hasNext();) {
|
||||
final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next();
|
||||
final int supportedVersion = factory.getSupportedVersion();
|
||||
if (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) {
|
||||
return Collections.singletonList(factory);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Collection<SVNAdminAreaFactory> factoriesFor14(final Collection factories) {
|
||||
final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2);
|
||||
for (Iterator iterator = factories.iterator(); iterator.hasNext();) {
|
||||
final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next();
|
||||
final int supportedVersion = factory.getSupportedVersion();
|
||||
if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) ||
|
||||
(WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion)) {
|
||||
result.add(factory);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Collection<SVNAdminAreaFactory> factoriesFor15(final Collection factories) {
|
||||
final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2);
|
||||
for (Iterator iterator = factories.iterator(); iterator.hasNext();) {
|
||||
final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next();
|
||||
final int supportedVersion = factory.getSupportedVersion();
|
||||
if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) ||
|
||||
(WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) ||
|
||||
(WorkingCopyFormat.ONE_DOT_FIVE.getFormat() == supportedVersion)) {
|
||||
result.add(factory);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String showUpgradeDialog(final File path, final Project project, final boolean display13format, final String mode,
|
||||
@NotNull final Ref<Boolean> wasOk) {
|
||||
assert ! ApplicationManager.getApplication().isUnitTestMode();
|
||||
final String[] newMode = new String[] {mode};
|
||||
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(new Runnable() {
|
||||
public void run() {
|
||||
wasOk.set(displayUpgradeDialog(project, path, display13format, newMode));
|
||||
}
|
||||
});
|
||||
ApplicationManager.getApplication().getMessageBus().syncPublisher(SvnVcs17.WC_CONVERTED).run();
|
||||
return newMode[0];
|
||||
}
|
||||
|
||||
public static WorkingCopyFormat getWorkingCopyFormat(final File path) {
|
||||
try {
|
||||
final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(path, true);
|
||||
if (SvnWcGeneration.V17.equals(svnWcGeneration)) return WorkingCopyFormat.ONE_DOT_SEVEN;
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
int format = 0;
|
||||
// it is enough to check parent and this.
|
||||
try {
|
||||
format = SVNAdminAreaFactory.checkWC(path, false);
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
if (format == 0 && path.getParentFile() != null) {
|
||||
format = SVNAdminAreaFactory.checkWC(path.getParentFile(), false);
|
||||
}
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
|
||||
return WorkingCopyFormat.getInstance(format);
|
||||
}
|
||||
|
||||
private static boolean displayUpgradeDialog(Project project, File path, final boolean dispay13format, String[] newMode) {
|
||||
UpgradeFormatDialog dialog = new UpgradeFormatDialog(project, path, false);
|
||||
dialog.setData(dispay13format, newMode[0]);
|
||||
dialog.show();
|
||||
if (dialog.isOK()) {
|
||||
newMode[0] = dialog.getUpgradeMode();
|
||||
}
|
||||
return dialog.isOK();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public class SvnHttpAuthMethodsDefaultChecker {
|
||||
private static final String AUTH_METHODS_PROPERTY = "svnkit.http.methods";
|
||||
private static final String OLD_AUTH_METHODS_PROPERTY = "javasvn.http.methods";
|
||||
|
||||
public static void check() {
|
||||
final String priorities = System.getProperty(AUTH_METHODS_PROPERTY, System.getProperty(OLD_AUTH_METHODS_PROPERTY));
|
||||
if (priorities == null) {
|
||||
System.setProperty(AUTH_METHODS_PROPERTY, "Basic,Digest,NTLM");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.persistent.SmallMapSerializer;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.branchConfig.InfoStorage;
|
||||
import org.jetbrains.idea.svn17.branchConfig.SvnBranchConfigurationNew;
|
||||
import org.jetbrains.idea.svn17.integrate.SvnBranchItem;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/24/11
|
||||
* Time: 1:21 PM
|
||||
*/
|
||||
public class SvnLoadedBrachesStorage17 {
|
||||
private final Object myLock;
|
||||
private SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>> myState;
|
||||
private final File myFile;
|
||||
private final Project myProject;
|
||||
|
||||
public SvnLoadedBrachesStorage17(final Project project) {
|
||||
myProject = project;
|
||||
final File vcsFile = new File(PathManager.getSystemPath(), "vcs");
|
||||
File file = new File(vcsFile, "svn_branches17");
|
||||
file.mkdirs();
|
||||
myFile = new File(file, project.getLocationHash());
|
||||
myLock = new Object();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Collection<SvnBranchItem> get(final String url) {
|
||||
synchronized (myLock) {
|
||||
if (myState == null) return null;
|
||||
Map<String, Collection<SvnBranchItem>> map = myState.get("");
|
||||
return map == null ? null : map.get(SvnBranchConfigurationNew.ensureEndSlash(url));
|
||||
}
|
||||
}
|
||||
|
||||
public void put(final String url, final Collection<SvnBranchItem> items) {
|
||||
synchronized (myLock) {
|
||||
if (myState == null) return;
|
||||
Map<String, Collection<SvnBranchItem>> map = myState.get("");
|
||||
if (map == null) {
|
||||
map = new HashMap<String, Collection<SvnBranchItem>>();
|
||||
myState.put("", map);
|
||||
}
|
||||
map.put(url, items);
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
synchronized (myLock) {
|
||||
myState = new SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>>(myFile, new EnumeratorStringDescriptor(), createExternalizer());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deactivate() {
|
||||
SvnBranchConfigurationManager17 manager = SvnBranchConfigurationManager17.getInstance(myProject);
|
||||
Map<VirtualFile,SvnBranchConfigurationNew> mapCopy = manager.getSvnBranchConfigManager().getMapCopy();
|
||||
for (Map.Entry<VirtualFile, SvnBranchConfigurationNew> entry : mapCopy.entrySet()) {
|
||||
Map<String,InfoStorage<List<SvnBranchItem>>> branchMap = entry.getValue().getBranchMap();
|
||||
for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> storageEntry : branchMap.entrySet()) {
|
||||
put(storageEntry.getKey(), storageEntry.getValue().getValue());
|
||||
}
|
||||
}
|
||||
synchronized (myLock) {
|
||||
myState.force();
|
||||
myState = null;
|
||||
}
|
||||
}
|
||||
|
||||
private DataExternalizer<Map<String, Collection<SvnBranchItem>>> createExternalizer() {
|
||||
return new DataExternalizer<Map<String, Collection<SvnBranchItem>>>() {
|
||||
@Override
|
||||
public void save(DataOutput out, Map<String, Collection<SvnBranchItem>> value) throws IOException {
|
||||
out.writeInt(value.size());
|
||||
ArrayList<String> keys = new ArrayList<String>(value.keySet());
|
||||
Collections.sort(keys);
|
||||
for (String key : keys) {
|
||||
out.writeUTF(key);
|
||||
List<SvnBranchItem> list = new ArrayList<SvnBranchItem>(value.get(key));
|
||||
Collections.sort(list, SerializationComparator.getInstance());
|
||||
out.writeInt(list.size());
|
||||
for (SvnBranchItem item : list) {
|
||||
out.writeUTF(item.getUrl());
|
||||
out.writeLong(item.getCreationDateMillis());
|
||||
out.writeLong(item.getRevision());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Collection<SvnBranchItem>> read(DataInput in) throws IOException {
|
||||
final HashMap<String, Collection<SvnBranchItem>> map = new HashMap<String, Collection<SvnBranchItem>>();
|
||||
int mapSize = in.readInt();
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
final String key = in.readUTF();
|
||||
final int size = in.readInt();
|
||||
final ArrayList<SvnBranchItem> list = new ArrayList<SvnBranchItem>(size);
|
||||
for (int j = 0; j < size; j++) {
|
||||
String url = in.readUTF();
|
||||
long creation = in.readLong();
|
||||
long revision = in.readLong();
|
||||
list.add(new SvnBranchItem(url, new Date(creation), revision));
|
||||
}
|
||||
map.put(key, list);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class SerializationComparator implements Comparator<SvnBranchItem> {
|
||||
private final static SerializationComparator ourInstance = new SerializationComparator();
|
||||
|
||||
public static SerializationComparator getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(SvnBranchItem o1, SvnBranchItem o2) {
|
||||
return o1.getUrl().compareToIgnoreCase(o2.getUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/24/11
|
||||
* Time: 1:07 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class SvnLoadedBranches {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.changes.LocallyDeletedChange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class SvnLocallyDeletedChange extends LocallyDeletedChange {
|
||||
private final ConflictState myConflictState;
|
||||
|
||||
public SvnLocallyDeletedChange(@NotNull final FilePath path, final ConflictState state) {
|
||||
super(path);
|
||||
myConflictState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getAddIcon() {
|
||||
return myConflictState.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
final String description = myConflictState.getDescription();
|
||||
if (description != null) {
|
||||
return SvnBundle.message("svn.changeview.locally.deleted.item.in.conflict.text", description);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
public ConflictState getConflictState() {
|
||||
return myConflictState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class SvnMapping {
|
||||
private final List<VirtualFile> myLonelyRoots;
|
||||
private final TreeMap<String, RootUrlInfo> myFile2UrlMap;
|
||||
private final Map<String, RootUrlInfo> myUrl2FileMap;
|
||||
private boolean myRootsDifferFromSettings;
|
||||
// no additional info. for caching only (convert roots)
|
||||
private List<VirtualFile> myPreCalculatedUnderVcsRoots;
|
||||
|
||||
public SvnMapping() {
|
||||
myFile2UrlMap = new TreeMap<String, RootUrlInfo>(FilePathsComparator.getInstance());
|
||||
myUrl2FileMap = new HashMap<String, RootUrlInfo>();
|
||||
myLonelyRoots = new ArrayList<VirtualFile>();
|
||||
|
||||
myPreCalculatedUnderVcsRoots = null;
|
||||
|
||||
myRootsDifferFromSettings = false;
|
||||
}
|
||||
|
||||
public void copyFrom(final SvnMapping other) {
|
||||
myFile2UrlMap.clear();
|
||||
myUrl2FileMap.clear();
|
||||
myLonelyRoots.clear();
|
||||
|
||||
myFile2UrlMap.putAll(other.myFile2UrlMap);
|
||||
myUrl2FileMap.putAll(other.myUrl2FileMap);
|
||||
myLonelyRoots.addAll(other.myLonelyRoots);
|
||||
myRootsDifferFromSettings = other.myRootsDifferFromSettings;
|
||||
myPreCalculatedUnderVcsRoots = null;
|
||||
}
|
||||
|
||||
public void addAll(final Collection<RootUrlInfo> roots) {
|
||||
for (RootUrlInfo rootInfo : roots) {
|
||||
final VirtualFile file = rootInfo.getVirtualFile();
|
||||
final File ioFile = new File(file.getPath());
|
||||
|
||||
myRootsDifferFromSettings |= ! rootInfo.getRoot().getPath().equals(file.getPath());
|
||||
|
||||
myFile2UrlMap.put(ioFile.getAbsolutePath(), rootInfo);
|
||||
myUrl2FileMap.put(rootInfo.getAbsoluteUrl(), rootInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(final RootUrlInfo rootInfo) {
|
||||
final VirtualFile file = rootInfo.getVirtualFile();
|
||||
final File ioFile = new File(file.getPath());
|
||||
|
||||
myRootsDifferFromSettings |= ! rootInfo.getRoot().getPath().equals(file.getPath());
|
||||
|
||||
myFile2UrlMap.put(ioFile.getAbsolutePath(), rootInfo);
|
||||
myUrl2FileMap.put(rootInfo.getAbsoluteUrl(), rootInfo);
|
||||
}
|
||||
|
||||
public List<VirtualFile> getUnderVcsRoots() {
|
||||
if (myPreCalculatedUnderVcsRoots == null) {
|
||||
myPreCalculatedUnderVcsRoots = new ArrayList<VirtualFile>();
|
||||
for (RootUrlInfo info : myFile2UrlMap.values()) {
|
||||
myPreCalculatedUnderVcsRoots.add(info.getVirtualFile());
|
||||
}
|
||||
}
|
||||
return myPreCalculatedUnderVcsRoots;
|
||||
}
|
||||
|
||||
public List<RootUrlInfo> getAllCopies() {
|
||||
return new ArrayList<RootUrlInfo>(myFile2UrlMap.values());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRootForPath(final String path) {
|
||||
String floor = myFile2UrlMap.floorKey(path);
|
||||
if (floor == null) return null;
|
||||
NavigableMap<String, RootUrlInfo> head = myFile2UrlMap.headMap(floor, true);
|
||||
for (String root : head.descendingKeySet()) {
|
||||
if (startsWithForPaths(root, path)) return root;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<String> getUrls() {
|
||||
return myUrl2FileMap.keySet();
|
||||
}
|
||||
|
||||
public RootUrlInfo byFile(final String path) {
|
||||
return myFile2UrlMap.get(path);
|
||||
}
|
||||
|
||||
public RootUrlInfo byUrl(final String url) {
|
||||
return myUrl2FileMap.get(url);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myUrl2FileMap.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isRootsDifferFromSettings() {
|
||||
return myRootsDifferFromSettings;
|
||||
}
|
||||
|
||||
public void reportLonelyRoots(final Collection<VirtualFile> roots) {
|
||||
myLonelyRoots.addAll(roots);
|
||||
}
|
||||
|
||||
public List<VirtualFile> getLonelyRoots() {
|
||||
return myLonelyRoots;
|
||||
}
|
||||
|
||||
private static class FilePathsComparator implements Comparator<String> {
|
||||
private final static FilePathsComparator ourInstance = new FilePathsComparator();
|
||||
|
||||
public static FilePathsComparator getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return FileUtil.comparePaths(o1, o2);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean startsWithForPaths(final String parent, final String child) {
|
||||
return SystemInfo.isFileSystemCaseSensitive ? child.startsWith(parent) : (StringUtil.startsWithIgnoreCase(child, parent));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SvnMappingSavedPart {
|
||||
public List<SvnCopyRootSimple> myMappingRoots;
|
||||
public List<SvnCopyRootSimple> myMoreRealMappingRoots;
|
||||
|
||||
public SvnMappingSavedPart() {
|
||||
myMappingRoots = new ArrayList<SvnCopyRootSimple>();
|
||||
myMoreRealMappingRoots = new ArrayList<SvnCopyRootSimple>();
|
||||
}
|
||||
|
||||
public void add(final SvnCopyRootSimple copy) {
|
||||
myMappingRoots.add(copy);
|
||||
}
|
||||
|
||||
public void addReal(final SvnCopyRootSimple copy) {
|
||||
myMoreRealMappingRoots.add(copy);
|
||||
}
|
||||
|
||||
public List<SvnCopyRootSimple> getMappingRoots() {
|
||||
return myMappingRoots;
|
||||
}
|
||||
|
||||
public List<SvnCopyRootSimple> getMoreRealMappingRoots() {
|
||||
return myMoreRealMappingRoots;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.AbstractFilterChildren;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
// referencies of RootUrlInfo will be kept; so type flag will be raised right in original object
|
||||
public class SvnNestedTypeRechecker {
|
||||
private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnNestedTypeRechecker");
|
||||
|
||||
private final MultiMap<VirtualFile, RootUrlInfo> myRoots;
|
||||
private final Map<String, RootUrlInfo> mySourceItems;
|
||||
private Map<String, Map<String, File>> myTreeTravellingMap;
|
||||
private final Project myProject;
|
||||
|
||||
public SvnNestedTypeRechecker(final Project project, final List<RootUrlInfo> roots) {
|
||||
myProject = project;
|
||||
final NestedGatherer nestedGatherer = new NestedGatherer();
|
||||
nestedGatherer.doFilter(new ArrayList<RootUrlInfo>(roots));
|
||||
myRoots = nestedGatherer.getNested();
|
||||
mySourceItems = new HashMap<String, RootUrlInfo>();
|
||||
for (VirtualFile root : myRoots.keySet()) {
|
||||
final Collection<RootUrlInfo> items = myRoots.get(root);
|
||||
for (RootUrlInfo item : items) {
|
||||
mySourceItems.put(FileUtil.nameToCompare(item.getVirtualFile().getPath()), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initTravellingMap() {
|
||||
myTreeTravellingMap = new HashMap<String, Map<String, File>>();
|
||||
|
||||
final MultiMap<VirtualFile, File> tmpMap = new MultiMap<VirtualFile, File>();
|
||||
for (VirtualFile parent : myRoots.keySet()) {
|
||||
final Collection<RootUrlInfo> children = myRoots.get(parent);
|
||||
for (RootUrlInfo child : children) {
|
||||
|
||||
VirtualFile current = child.getVirtualFile();
|
||||
while (! current.equals(parent)) {
|
||||
tmpMap.putValue(current.getParent(), new File(current.getPath()));
|
||||
current = current.getParent();
|
||||
if (current.getParent() == null) break; //+-
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (VirtualFile dir : tmpMap.keySet()) {
|
||||
final Map<String, File> currMap = new HashMap<String, File>();
|
||||
final Collection<File> coll = tmpMap.get(dir);
|
||||
for (File file : coll) {
|
||||
currMap.put(file.getAbsolutePath(), file);
|
||||
}
|
||||
myTreeTravellingMap.put(FileUtil.nameToCompare(dir.getPath()), currMap);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (! myRoots.isEmpty()) {
|
||||
initTravellingMap();
|
||||
|
||||
final ISVNStatusFileProvider fileProvider = new ISVNStatusFileProvider() {
|
||||
public Map getChildrenFiles(File parent) {
|
||||
final Map<String, File> children = myTreeTravellingMap.get(FileUtil.nameToCompare(parent.getAbsolutePath()));
|
||||
return children == null ? Collections.emptyMap() : children;
|
||||
}
|
||||
};
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(myProject);
|
||||
final SVNStatusClient client = vcs.createStatusClient();
|
||||
client.setFilesProvider(fileProvider);
|
||||
|
||||
for (VirtualFile parent : myRoots.keySet()) {
|
||||
try {
|
||||
client.doStatus(new File(parent.getPath()), SVNRevision.WORKING, SVNDepth.INFINITY, false, true, true, false, new ISVNStatusHandler() {
|
||||
public void handleStatus(final SVNStatus status) throws SVNException {
|
||||
final boolean switched = status.isSwitched();
|
||||
final boolean externals = SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_EXTERNAL);
|
||||
|
||||
if (switched || externals) {
|
||||
final RootUrlInfo urlInfo = mySourceItems.get(FileUtil.nameToCompare(status.getFile().getAbsolutePath()));
|
||||
if (urlInfo != null) {
|
||||
if (switched) {
|
||||
urlInfo.setType(NestedCopyType.switched);
|
||||
} else {
|
||||
urlInfo.setType(NestedCopyType.external);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*private static SVNStatus getExternalItemStatus(final SvnVcs vcs, final File file) {
|
||||
final SVNStatusClient statusClient = vcs.createStatusClient();
|
||||
try {
|
||||
if (file.isDirectory()) {
|
||||
return statusClient.doStatus(file, false);
|
||||
} else {
|
||||
final File parent = file.getParentFile();
|
||||
if (parent != null) {
|
||||
statusClient.setFilesProvider(new ISVNStatusFileProvider() {
|
||||
public Map getChildrenFiles(File parent) {
|
||||
return Collections.singletonMap(file.getAbsolutePath(), file);
|
||||
}
|
||||
});
|
||||
final Ref<SVNStatus> refStatus = new Ref<SVNStatus>();
|
||||
statusClient.doStatus(parent, SVNRevision.WORKING, SVNDepth.FILES, false, true, false, false, new ISVNStatusHandler() {
|
||||
public void handleStatus(final SVNStatus status) throws SVNException {
|
||||
if (file.equals(status.getFile())) {
|
||||
refStatus.set(status);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
return refStatus.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
|
||||
private static class NestedGatherer extends AbstractFilterChildren<RootUrlInfo> {
|
||||
private final MultiMap<VirtualFile, RootUrlInfo> myNested;
|
||||
|
||||
private NestedGatherer() {
|
||||
myNested = new MultiMap<VirtualFile, RootUrlInfo>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sortAscending(List<RootUrlInfo> rootUrlInfos) {
|
||||
Collections.sort(rootUrlInfos, new Comparator<RootUrlInfo>() {
|
||||
public int compare(final RootUrlInfo r1, final RootUrlInfo r2) {
|
||||
return new Integer(r1.getVirtualFile().getPath().length()).compareTo(r2.getVirtualFile().getPath().length());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAncestor(RootUrlInfo parent, RootUrlInfo child) {
|
||||
final boolean result = VfsUtil.isAncestor(parent.getVirtualFile(), child.getVirtualFile(), true);
|
||||
if (result) {
|
||||
myNested.putValue(parent.getVirtualFile(), child);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public MultiMap<VirtualFile, RootUrlInfo> getNested() {
|
||||
return myNested;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import org.tmatesoft.svn.core.SVNCancelException;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNEvent;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class SvnProgressCanceller implements ISVNEventHandler {
|
||||
public void checkCancelled() throws SVNCancelException {
|
||||
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (indicator != null && indicator.isCanceled()) {
|
||||
throw new SVNCancelException();
|
||||
}
|
||||
}
|
||||
|
||||
public void handleEvent(final SVNEvent event, final double progress) throws SVNException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public interface SvnPropertyKeys {
|
||||
String SVN_EOL_STYLE = "svn:eol-style";
|
||||
String SVN_KEYWORDS = "svn:keywords";
|
||||
String SVN_NEEDS_LOCK = "svn:needs-lock";
|
||||
String SVN_MIME_TYPE = "svn:mime-type";
|
||||
String SVN_EXECUTABLE = "svn:executable";
|
||||
String SVN_IGNORE = "svn:ignore";
|
||||
String SVN_EXTERNALS = "svn:externals";
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.impl.GenericNotifierImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// todo be done
|
||||
// todo : two kinds. positive: either into common proxy, or into system properties
|
||||
public class SvnProxyAuthenticationNotifier extends GenericNotifierImpl<String, String> {
|
||||
public SvnProxyAuthenticationNotifier(Project project, @NotNull String groupId, @NotNull String title, @NotNull NotificationType type) {
|
||||
super(project, groupId, title, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ask(String obj, String description) {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getKey(String obj) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getNotificationContent(String obj) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getToString(String obj) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.tmatesoft.svn.core.SVNDepth;
|
||||
import org.tmatesoft.svn.core.SVNErrorCode;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNNodeKind;
|
||||
import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class SvnRecursiveStatusWalker {
|
||||
private final StatusWalkerPartner myPartner;
|
||||
private final StatusReceiver myReceiver;
|
||||
private final LinkedList<MyItem> myQueue;
|
||||
private final MyHandler myHandler;
|
||||
|
||||
public SvnRecursiveStatusWalker(final StatusReceiver receiver, final StatusWalkerPartner partner) {
|
||||
myReceiver = receiver;
|
||||
myPartner = partner;
|
||||
myQueue = new LinkedList<MyItem>();
|
||||
myHandler = new MyHandler();
|
||||
}
|
||||
|
||||
public void go(final FilePath rootPath, final SVNDepth depth) throws SVNException {
|
||||
final MyItem root = new MyItem(rootPath, depth, myPartner.createStatusClient(), false);
|
||||
myQueue.add(root);
|
||||
|
||||
while (! myQueue.isEmpty()) {
|
||||
myPartner.checkCanceled();
|
||||
|
||||
final MyItem item = myQueue.removeFirst();
|
||||
final FilePath path = item.getPath();
|
||||
final File ioFile = path.getIOFile();
|
||||
|
||||
if (path.isDirectory()) {
|
||||
myHandler.setCurrentItem(item);
|
||||
try {
|
||||
item.getClient().doStatus(ioFile, SVNRevision.WORKING, item.getDepth(), false, false, true, false, myHandler, null);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
if (e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_NOT_DIRECTORY) {
|
||||
final VirtualFile virtualFile = path.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
if (myPartner.isExcluded(virtualFile)) return;
|
||||
// self is unversioned
|
||||
myReceiver.processUnversioned(virtualFile);
|
||||
|
||||
processRecursively(virtualFile, item.getDepth());
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item.isIsInnerCopyRoot()) {
|
||||
// this means that the status of parent directory had already been checked and is unversioned;
|
||||
// to avoid SVN exception on status query to unversioned directory; and since we already know then that the file
|
||||
// status is "unversioned" -> just register the unversioned file
|
||||
if (path.getVirtualFile() != null) {
|
||||
myReceiver.processUnversioned(path.getVirtualFile());
|
||||
}
|
||||
} else {
|
||||
final SVNStatus status = item.getClient().doStatus(ioFile, false, false);
|
||||
myReceiver.process(path, status, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyItem {
|
||||
private final FilePath myPath;
|
||||
private final SVNDepth myDepth;
|
||||
private final SVNStatusClient myClient;
|
||||
private final boolean myIsInnerCopyRoot;
|
||||
|
||||
private MyItem(FilePath path, SVNDepth depth, SVNStatusClient client, boolean isInnerCopyRoot) {
|
||||
myPath = path;
|
||||
myDepth = depth;
|
||||
myClient = client;
|
||||
myIsInnerCopyRoot = isInnerCopyRoot;
|
||||
}
|
||||
|
||||
public FilePath getPath() {
|
||||
return myPath;
|
||||
}
|
||||
|
||||
public SVNDepth getDepth() {
|
||||
return myDepth;
|
||||
}
|
||||
|
||||
public SVNStatusClient getClient() {
|
||||
return myClient;
|
||||
}
|
||||
|
||||
public boolean isIsInnerCopyRoot() {
|
||||
return myIsInnerCopyRoot;
|
||||
}
|
||||
}
|
||||
|
||||
private void processRecursively(final VirtualFile vFile, final SVNDepth prevDepth) {
|
||||
if (SVNDepth.EMPTY.equals(prevDepth)) return;
|
||||
if (myPartner.isIgnoredIdeaLevel(vFile)) {
|
||||
myReceiver.processIgnored(vFile);
|
||||
return;
|
||||
}
|
||||
final SVNDepth newDepth = SVNDepth.INFINITY.equals(prevDepth) ? SVNDepth.INFINITY : SVNDepth.EMPTY;
|
||||
|
||||
final SVNStatusClient childClient = myPartner.createStatusClient();
|
||||
final VirtualFile[] children = vFile.getChildren();
|
||||
for (VirtualFile child : children) {
|
||||
final FilePath filePath = VcsUtil.getFilePath(child.getPath(), child.isDirectory());
|
||||
// recursiveness is used ONLY for search of working copies that have unversioned files above
|
||||
final MyItem childItem = new MyItem(filePath, newDepth, childClient, true);
|
||||
myQueue.add(childItem);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyHandler implements ISVNStatusHandler {
|
||||
private MyItem myCurrentItem;
|
||||
|
||||
public void setCurrentItem(MyItem currentItem) {
|
||||
myCurrentItem = currentItem;
|
||||
}
|
||||
|
||||
public void handleStatus(final SVNStatus status) throws SVNException {
|
||||
myPartner.checkCanceled();
|
||||
final FilePath path = VcsUtil.getFilePath(status.getFile(), status.getKind().equals(SVNNodeKind.DIR));
|
||||
final VirtualFile vFile = path.getVirtualFile();
|
||||
|
||||
if ((vFile != null) && myPartner.isExcluded(vFile)) return;
|
||||
|
||||
if ((vFile != null) && (SvnVcs17.svnStatusIsUnversioned(status))) {
|
||||
myReceiver.processUnversioned(vFile);
|
||||
if (vFile.isDirectory()) {
|
||||
processRecursively(vFile, myCurrentItem.getDepth());
|
||||
}
|
||||
} else {
|
||||
myReceiver.process(path, status, myCurrentItem.isIsInnerCopyRoot());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
/**
|
||||
* @author alex
|
||||
*/
|
||||
public class SvnRevisionNumber implements VcsRevisionNumber {
|
||||
@NotNull
|
||||
private final SVNRevision myRevision;
|
||||
|
||||
public SvnRevisionNumber(@NotNull SVNRevision revision) {
|
||||
myRevision = revision;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
return myRevision.toString();
|
||||
}
|
||||
|
||||
public int compareTo(VcsRevisionNumber vcsRevisionNumber) {
|
||||
if (vcsRevisionNumber == null || vcsRevisionNumber.getClass() != SvnRevisionNumber.class) {
|
||||
return -1;
|
||||
}
|
||||
SVNRevision rev = ((SvnRevisionNumber)vcsRevisionNumber).myRevision;
|
||||
if (!myRevision.isValid()) {
|
||||
return !rev.isValid() ? 0 : -1;
|
||||
}
|
||||
if (myRevision.getNumber() >= 0 && rev.getNumber() >= 0) {
|
||||
return myRevision.getNumber() == rev.getNumber() ? 0 : myRevision.getNumber() > rev.getNumber() ? 1 : -1;
|
||||
}
|
||||
else if (myRevision.getDate() != null && rev.getDate() != null) {
|
||||
return myRevision.getDate().compareTo(rev.getDate());
|
||||
}
|
||||
if (myRevision.equals(SVNRevision.HEAD)) {
|
||||
return rev.equals(SVNRevision.HEAD) ? 0 : 1; // HEAD is greater than a specific rev
|
||||
}
|
||||
return myRevision.getID() == rev.getID() ? 0 : myRevision.getID() > rev.getID() ? 1 : -1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SVNRevision getRevision() {
|
||||
return myRevision;
|
||||
}
|
||||
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final SvnRevisionNumber that = (SvnRevisionNumber)o;
|
||||
|
||||
return myRevision.equals(that.myRevision);
|
||||
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myRevision.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return myRevision.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScope;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SvnScopeZipper implements Runnable {
|
||||
private final VcsDirtyScope myIn;
|
||||
private final List<FilePath> myRecursiveDirs;
|
||||
// instead of set and heavy equals of file path
|
||||
private final Map<String, MyDirNonRecursive> myNonRecursiveDirs;
|
||||
// those alone in their immediate parent
|
||||
private final List<FilePath> mySingleFiles;
|
||||
|
||||
public SvnScopeZipper(final VcsDirtyScope in) {
|
||||
myIn = in;
|
||||
myRecursiveDirs = new ArrayList<FilePath>(in.getRecursivelyDirtyDirectories());
|
||||
myNonRecursiveDirs = new HashMap<String, MyDirNonRecursive>();
|
||||
mySingleFiles = new ArrayList<FilePath>();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// if put directly into dirty scope, to access a copy will be created every time
|
||||
final Set<FilePath> files = myIn.getDirtyFilesNoExpand();
|
||||
|
||||
for (FilePath file : files) {
|
||||
if (file.isDirectory()) {
|
||||
final VirtualFile vFile = file.getVirtualFile();
|
||||
// todo take care about this 'not valid' - right now keeping things as they used to be
|
||||
if (vFile != null && vFile.isValid()) {
|
||||
final MyDirNonRecursive me = createOrGet(file);
|
||||
me.setInterestedInParent(true);
|
||||
for (VirtualFile child : vFile.getChildren()) {
|
||||
me.add(new FilePathImpl(child));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final FilePath parent = file.getParentPath();
|
||||
if (parent != null) {
|
||||
final MyDirNonRecursive item = createOrGet(parent);
|
||||
item.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move alone files into a separate list
|
||||
/*for (Iterator<Map.Entry<String, MyDirNonRecursive>> iterator = myNonRecursiveDirs.entrySet().iterator(); iterator.hasNext();) {
|
||||
final Map.Entry<String, MyDirNonRecursive> entry = iterator.next();
|
||||
final MyDirNonRecursive item = entry.getValue();
|
||||
if ((! item.isInterestedInParent()) && (item.getChildrenList().size() == 1)) {
|
||||
iterator.remove();
|
||||
mySingleFiles.add(item.getChildrenList().iterator().next());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private MyDirNonRecursive createOrGet(final FilePath parent) {
|
||||
final String key = getKey(parent);
|
||||
final MyDirNonRecursive result = myNonRecursiveDirs.get(key);
|
||||
if (result != null) return result;
|
||||
final MyDirNonRecursive newItem = new MyDirNonRecursive(parent);
|
||||
myNonRecursiveDirs.put(key, newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
public List<FilePath> getRecursiveDirs() {
|
||||
return myRecursiveDirs;
|
||||
}
|
||||
|
||||
public Map<String, MyDirNonRecursive> getNonRecursiveDirs() {
|
||||
return myNonRecursiveDirs;
|
||||
}
|
||||
|
||||
public List<FilePath> getSingleFiles() {
|
||||
return mySingleFiles;
|
||||
}
|
||||
|
||||
static class MyDirNonRecursive {
|
||||
private boolean myInterestedInParent;
|
||||
private final FilePath myDir;
|
||||
// instead of set and heavy equals of file path
|
||||
private final Map<String, FilePath> myChildren;
|
||||
|
||||
private MyDirNonRecursive(final FilePath dir) {
|
||||
myDir = dir;
|
||||
myChildren = new HashMap<String, FilePath>();
|
||||
}
|
||||
|
||||
public boolean isInterestedInParent() {
|
||||
return myInterestedInParent;
|
||||
}
|
||||
|
||||
public void setInterestedInParent(boolean interestedInParent) {
|
||||
myInterestedInParent = interestedInParent;
|
||||
}
|
||||
|
||||
public void add(final FilePath path) {
|
||||
myChildren.put(getKey(path), path);
|
||||
}
|
||||
|
||||
public Collection<FilePath> getChildrenList() {
|
||||
return myChildren.values();
|
||||
}
|
||||
|
||||
public FilePath getDir() {
|
||||
return myDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getKey(final FilePath path) {
|
||||
return path.getPresentableUrl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.jetbrains.idea.svn17.config.DefaultProxyGroup;
|
||||
import org.jetbrains.idea.svn17.config.ProxyGroup;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public interface SvnServerFileManager {
|
||||
DefaultProxyGroup getDefaultGroup();
|
||||
Map<String, ProxyGroup> getGroups();
|
||||
|
||||
void updateUserServerFile(final Collection<ProxyGroup> newUserGroups);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.jetbrains.idea.svn17.config.DefaultProxyGroup;
|
||||
import org.jetbrains.idea.svn17.config.ProxyGroup;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SvnServerFileManagerImpl implements SvnServerFileManager {
|
||||
private final DefaultProxyGroup myDefaultGroup;
|
||||
private final Map<String, ProxyGroup> myGroups;
|
||||
private final IdeaSVNConfigFile myFile;
|
||||
|
||||
public SvnServerFileManagerImpl(final IdeaSVNConfigFile file) {
|
||||
myFile = file;
|
||||
myFile.updateGroups();
|
||||
|
||||
myGroups = new HashMap<String, ProxyGroup>();
|
||||
myGroups.putAll(file.getAllGroups());
|
||||
myDefaultGroup = file.getDefaultGroup();
|
||||
}
|
||||
|
||||
public DefaultProxyGroup getDefaultGroup() {
|
||||
return (DefaultProxyGroup) myDefaultGroup.copy();
|
||||
}
|
||||
|
||||
public Map<String, ProxyGroup> getGroups() {
|
||||
// return deep copy
|
||||
final Map<String, ProxyGroup> result = new HashMap<String, ProxyGroup>(myGroups);
|
||||
for (Map.Entry<String, ProxyGroup> entry : myGroups.entrySet()) {
|
||||
result.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void updateUserServerFile(final Collection<ProxyGroup> newUserGroups) {
|
||||
final Map<String, ProxyGroup> oldGroups = getGroups();
|
||||
|
||||
for (ProxyGroup proxyGroup : newUserGroups) {
|
||||
if (proxyGroup.isDefault()) {
|
||||
processGroup(proxyGroup, getDefaultGroup(), false);
|
||||
} else {
|
||||
findAndProcessGroup(proxyGroup, oldGroups);
|
||||
}
|
||||
}
|
||||
|
||||
for (String groupName : oldGroups.keySet()) {
|
||||
myFile.deleteGroup(groupName);
|
||||
}
|
||||
|
||||
myFile.save();
|
||||
}
|
||||
|
||||
private void processGroup(final ProxyGroup newGroup, final ProxyGroup oldGroup, final boolean groupWasAdded) {
|
||||
final String newGroupName = newGroup.getName();
|
||||
if (groupWasAdded) {
|
||||
myFile.addGroup(newGroupName, newGroup.getPatterns(), newGroup.getProperties());
|
||||
} else {
|
||||
final Map<String, String> oldProperties = oldGroup.getProperties();
|
||||
final Map<String, String> newProperties = newGroup.getProperties();
|
||||
|
||||
final Set<String> deletedProperties = new HashSet<String>();
|
||||
for (String oldKey : oldProperties.keySet()) {
|
||||
if (! newProperties.containsKey(oldKey)) {
|
||||
deletedProperties.add(oldKey);
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, String> newOrModifiedProperties = new HashMap<String, String>();
|
||||
for (Map.Entry<String, String> entry : newProperties.entrySet()) {
|
||||
final String oldValue = oldProperties.get(entry.getKey());
|
||||
if ((oldValue == null) || (! oldValue.equals(entry.getValue()))) {
|
||||
newOrModifiedProperties.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
myFile.modifyGroup(newGroupName, newGroup.getPatterns(), deletedProperties, newOrModifiedProperties, newGroup.isDefault());
|
||||
}
|
||||
}
|
||||
|
||||
private void findAndProcessGroup(final ProxyGroup newGroup, final Map<String, ProxyGroup> oldGroups) {
|
||||
final String newGroupName = newGroup.getName();
|
||||
final ProxyGroup oldGroup = oldGroups.get(newGroupName);
|
||||
final boolean groupWasAdded = (oldGroup == null) && (! newGroup.isDefault());
|
||||
if (! groupWasAdded) {
|
||||
// to track deleted
|
||||
oldGroups.remove(newGroupName);
|
||||
}
|
||||
processGroup(newGroup, oldGroup, groupWasAdded);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatus;
|
||||
import org.tmatesoft.svn.core.wc.SVNStatusType;
|
||||
|
||||
public class SvnStatusConvertor {
|
||||
private SvnStatusConvertor() {
|
||||
}
|
||||
|
||||
public static FileStatus convertStatus(final SVNStatus status) throws SVNException {
|
||||
if (status == null) {
|
||||
return FileStatus.UNKNOWN;
|
||||
}
|
||||
if (SvnVcs17.svnStatusIsUnversioned(status)) {
|
||||
return FileStatus.UNKNOWN;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_MISSING)) {
|
||||
return FileStatus.DELETED_FROM_FS;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_EXTERNAL)) {
|
||||
return SvnFileStatus.EXTERNAL;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_OBSTRUCTED)) {
|
||||
return SvnFileStatus.OBSTRUCTED;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_IGNORED)) {
|
||||
return FileStatus.IGNORED;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_ADDED)) {
|
||||
return FileStatus.ADDED;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_DELETED)) {
|
||||
return FileStatus.DELETED;
|
||||
}
|
||||
else if (SvnVcs17.svnStatusIs(status, SVNStatusType.STATUS_REPLACED)) {
|
||||
return SvnFileStatus.REPLACED;
|
||||
}
|
||||
else if (status.getContentsStatus() == SVNStatusType.STATUS_CONFLICTED ||
|
||||
status.getPropertiesStatus() == SVNStatusType.STATUS_CONFLICTED) {
|
||||
if (status.getContentsStatus() == SVNStatusType.STATUS_CONFLICTED &&
|
||||
status.getPropertiesStatus() == SVNStatusType.STATUS_CONFLICTED) {
|
||||
return FileStatus.MERGED_WITH_BOTH_CONFLICTS;
|
||||
} else if (status.getContentsStatus() == SVNStatusType.STATUS_CONFLICTED) {
|
||||
return FileStatus.MERGED_WITH_CONFLICTS;
|
||||
}
|
||||
return FileStatus.MERGED_WITH_PROPERTY_CONFLICTS;
|
||||
}
|
||||
else if (status.getContentsStatus() == SVNStatusType.STATUS_MODIFIED ||
|
||||
status.getPropertiesStatus() == SVNStatusType.STATUS_MODIFIED) {
|
||||
return FileStatus.MODIFIED;
|
||||
}
|
||||
else if (status.isSwitched()) {
|
||||
return FileStatus.SWITCHED;
|
||||
}
|
||||
else if (status.isCopied()) {
|
||||
return FileStatus.ADDED;
|
||||
}
|
||||
return FileStatus.NOT_CHANGED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.FileStatusManager;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
public class SvnStatusUtil {
|
||||
private SvnStatusUtil() {
|
||||
}
|
||||
|
||||
public static boolean isUnderControl(final Project project, final VirtualFile file) {
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(project);
|
||||
return (! isIgnoredInAnySense(clManager, file)) && (! clManager.isUnversioned(file));
|
||||
}
|
||||
|
||||
public static boolean isAdded(final Project project, final VirtualFile file) {
|
||||
final FileStatus status = FileStatusManager.getInstance(project).getStatus(file);
|
||||
return FileStatus.ADDED.equals(status);
|
||||
}
|
||||
|
||||
public static boolean isExplicitlyLocked(final Project project, final VirtualFile file) {
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(project);
|
||||
return ((ChangeListManagerImpl) clManager).isLogicallyLocked(file);
|
||||
}
|
||||
|
||||
public static boolean isIgnoredInAnySense(final ChangeListManager clManager, final VirtualFile file) {
|
||||
return clManager.isIgnoredFile(file) || FileStatus.IGNORED.equals(clManager.getStatus(file));
|
||||
}
|
||||
|
||||
public static boolean fileCanBeAdded(final Project project, final VirtualFile file) {
|
||||
final ChangeListManager clManager = ChangeListManager.getInstance(project);
|
||||
return isIgnoredInAnySense(clManager, file) || clManager.isUnversioned(file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.AbstractVcsHelper;
|
||||
import com.intellij.openapi.vcs.RepositoryLocation;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn17.branchConfig.SvnBranchConfigurationNew;
|
||||
import org.jetbrains.idea.svn17.dialogs.LockDialog;
|
||||
import org.jetbrains.idea.svn17.dialogs.WCInfo;
|
||||
import org.tmatesoft.svn.core.*;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
|
||||
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
|
||||
import org.tmatesoft.svn.core.io.SVNCapability;
|
||||
import org.tmatesoft.svn.core.io.SVNRepository;
|
||||
import org.tmatesoft.svn.core.wc.*;
|
||||
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
public class SvnUtil {
|
||||
@NonNls public static final String SVN_ADMIN_DIR_NAME = SVNFileUtil.getAdminDirectoryName();
|
||||
@NonNls public static final String ENTRIES_FILE_NAME = "entries";
|
||||
@NonNls public static final String DIR_PROPS_FILE_NAME = "dir-props";
|
||||
@NonNls public static final String PATH_TO_LOCK_FILE = SVN_ADMIN_DIR_NAME + "/lock";
|
||||
@NonNls public static final String LOCK_FILE_NAME = "lock";
|
||||
|
||||
private SvnUtil() {
|
||||
}
|
||||
|
||||
public static void crawlWCRoots(VirtualFile path, NotNullFunction<VirtualFile, Collection<VirtualFile>> callback) {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
final boolean isDirectory = path.isDirectory();
|
||||
final VirtualFile parentVFile = (!isDirectory) || (!path.exists()) ? path.getParent() : path;
|
||||
if (parentVFile == null) {
|
||||
return;
|
||||
}
|
||||
final File parent = new File(parentVFile.getPath());
|
||||
|
||||
if (isSvnVersioned(parent)) {
|
||||
checkCanceled();
|
||||
final Collection<VirtualFile> pending = callback.fun(path);
|
||||
checkCanceled();
|
||||
for (VirtualFile virtualFile : pending) {
|
||||
crawlWCRoots(virtualFile, callback);
|
||||
}
|
||||
} else if (isDirectory) {
|
||||
checkCanceled();
|
||||
VirtualFile[] children = path.getChildren();
|
||||
for (int i = 0; children != null && i < children.length; i++) {
|
||||
checkCanceled();
|
||||
VirtualFile child = children[i];
|
||||
if (child.isDirectory()) {
|
||||
crawlWCRoots(child, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSvnVersioned(File parent) {
|
||||
return SVNWCUtil.isVersionedDirectory(parent) || is17CopyPart(parent);
|
||||
}
|
||||
|
||||
public static Collection<VirtualFile> crawlWCRoots(File path, SvnWCRootCrawler callback, ProgressIndicator progress) {
|
||||
final LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
VirtualFile vf = lfs.findFileByIoFile(path);
|
||||
if (vf == null) {
|
||||
vf = lfs.refreshAndFindFileByIoFile(path);
|
||||
}
|
||||
if (vf == null) return Collections.emptyList();
|
||||
return crawlWCRoots(vf, callback, progress);
|
||||
}
|
||||
|
||||
private static Collection<VirtualFile> crawlWCRoots(VirtualFile vf, SvnWCRootCrawler callback, ProgressIndicator progress) {
|
||||
final Collection<VirtualFile> result = new HashSet<VirtualFile>();
|
||||
final boolean isDirectory = vf.isDirectory();
|
||||
VirtualFile parent = ! isDirectory || !vf.exists() ? vf.getParent() : vf;
|
||||
|
||||
final File parentIo = new File(parent.getPath());
|
||||
if (isSvnVersioned(parentIo)) {
|
||||
checkCanceled(progress);
|
||||
callback.handleWorkingCopyRoot(parentIo, progress);
|
||||
checkCanceled(progress);
|
||||
result.add(parent);
|
||||
} else if (isDirectory) {
|
||||
checkCanceled(progress);
|
||||
final VirtualFile[] childrenVF = parent.getChildren();
|
||||
for (VirtualFile file : childrenVF) {
|
||||
checkCanceled(progress);
|
||||
if (file.isDirectory()) {
|
||||
result.addAll(crawlWCRoots(file, callback, progress));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void checkCanceled() {
|
||||
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
checkCanceled(indicator);
|
||||
}
|
||||
|
||||
private static void checkCanceled(final ProgressIndicator progress) {
|
||||
if (progress != null && progress.isCanceled()) {
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getLocationsForModule(final SvnVcs17 vcs, File path, ProgressIndicator progress) {
|
||||
LocationsCrawler crawler = new LocationsCrawler(vcs);
|
||||
crawlWCRoots(path, crawler, progress);
|
||||
return crawler.getLocations();
|
||||
}
|
||||
|
||||
public static Map<String, File> getLocationInfoForModule(final SvnVcs17 vcs, File path, ProgressIndicator progress) {
|
||||
final LocationsCrawler crawler = new LocationsCrawler(vcs);
|
||||
crawlWCRoots(path, crawler, progress);
|
||||
return crawler.getLocationInfos();
|
||||
}
|
||||
|
||||
public static void doLockFiles(Project project, final SvnVcs17 activeVcs, final File[] ioFiles) throws VcsException {
|
||||
final String lockMessage;
|
||||
final boolean force;
|
||||
// TODO[yole]: check for shift pressed
|
||||
if (activeVcs.getCheckoutOptions().getValue()) {
|
||||
LockDialog dialog = new LockDialog(project, true, ioFiles != null && ioFiles.length > 1);
|
||||
dialog.show();
|
||||
if (!dialog.isOK()) {
|
||||
return;
|
||||
}
|
||||
lockMessage = dialog.getComment();
|
||||
force = dialog.isForce();
|
||||
}
|
||||
else {
|
||||
lockMessage = "";
|
||||
force = false;
|
||||
}
|
||||
|
||||
final SVNException[] exception = new SVNException[1];
|
||||
final Collection<String> failedLocks = new ArrayList<String>();
|
||||
final int[] count = new int[]{ioFiles.length};
|
||||
final ISVNEventHandler eventHandler = new ISVNEventHandler() {
|
||||
public void handleEvent(SVNEvent event, double progress) {
|
||||
if (event.getAction() == SVNEventAction.LOCK_FAILED) {
|
||||
failedLocks.add(event.getErrorMessage() != null ?
|
||||
event.getErrorMessage().getFullMessage() :
|
||||
event.getFile().getAbsolutePath());
|
||||
count[0]--;
|
||||
}
|
||||
}
|
||||
|
||||
public void checkCancelled() {
|
||||
}
|
||||
};
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
SVNWCClient wcClient;
|
||||
|
||||
try {
|
||||
wcClient = activeVcs.createWCClient();
|
||||
wcClient.setEventHandler(eventHandler);
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.locking.files"));
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
File file = ioFile;
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", file.getName()));
|
||||
}
|
||||
wcClient.doLock(new File[]{file}, force, lockMessage);
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(command, SvnBundle.message("progress.title.lock.files"), false, project);
|
||||
if (!failedLocks.isEmpty()) {
|
||||
String[] failedFiles = ArrayUtil.toStringArray(failedLocks);
|
||||
List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
|
||||
for (String file : failedFiles) {
|
||||
exceptions.add(new VcsException(SvnBundle.message("exception.text.locking.file.failed", file)));
|
||||
}
|
||||
AbstractVcsHelper.getInstance(project).showErrors(exceptions, SvnBundle.message("message.title.lock.failures"));
|
||||
}
|
||||
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo(SvnBundle.message("message.text.files.locked", count[0]));
|
||||
if (exception[0] != null) {
|
||||
throw new VcsException(exception[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void doUnlockFiles(Project project, final SvnVcs17 activeVcs, final File[] ioFiles) throws VcsException {
|
||||
final boolean force = true;
|
||||
final SVNException[] exception = new SVNException[1];
|
||||
final Collection<String> failedUnlocks = new ArrayList<String>();
|
||||
final int[] count = new int[]{ioFiles.length};
|
||||
final ISVNEventHandler eventHandler = new ISVNEventHandler() {
|
||||
public void handleEvent(SVNEvent event, double progress) {
|
||||
if (event.getAction() == SVNEventAction.UNLOCK_FAILED) {
|
||||
failedUnlocks.add(event.getErrorMessage() != null ?
|
||||
event.getErrorMessage().getFullMessage() :
|
||||
event.getFile().getAbsolutePath());
|
||||
count[0]--;
|
||||
}
|
||||
}
|
||||
|
||||
public void checkCancelled() {
|
||||
}
|
||||
};
|
||||
|
||||
Runnable command = new Runnable() {
|
||||
public void run() {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
SVNWCClient wcClient;
|
||||
|
||||
try {
|
||||
wcClient = activeVcs.createWCClient();
|
||||
wcClient.setEventHandler(eventHandler);
|
||||
if (progress != null) {
|
||||
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
|
||||
}
|
||||
for (File ioFile : ioFiles) {
|
||||
if (progress != null) {
|
||||
progress.checkCanceled();
|
||||
}
|
||||
File file = ioFile;
|
||||
if (progress != null) {
|
||||
progress.setText2(SvnBundle.message("progress.text2.processing.file", file.getName()));
|
||||
}
|
||||
wcClient.doUnlock(new File[]{file}, force);
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
exception[0] = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(command, SvnBundle.message("progress.title.unlock.files"), false, project);
|
||||
if (!failedUnlocks.isEmpty()) {
|
||||
String[] failedFiles = ArrayUtil.toStringArray(failedUnlocks);
|
||||
List<VcsException> exceptions = new ArrayList<VcsException>();
|
||||
|
||||
for (String file : failedFiles) {
|
||||
exceptions.add(new VcsException(SvnBundle.message("exception.text.failed.to.unlock.file", file)));
|
||||
}
|
||||
AbstractVcsHelper.getInstance(project).showErrors(exceptions, SvnBundle.message("message.title.unlock.failures"));
|
||||
}
|
||||
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo(SvnBundle.message("message.text.files.unlocked", count[0]));
|
||||
if (exception[0] != null) {
|
||||
throw new VcsException(exception[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatRepresentation(final WorkingCopyFormat format) {
|
||||
if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) {
|
||||
return SvnBundle.message("dialog.show.svn.map.table.version16.text");
|
||||
} else if (WorkingCopyFormat.ONE_DOT_FIVE.equals(format)) {
|
||||
return SvnBundle.message("dialog.show.svn.map.table.version15.text");
|
||||
} else if (WorkingCopyFormat.ONE_DOT_FOUR.equals(format)) {
|
||||
return SvnBundle.message("dialog.show.svn.map.table.version14.text");
|
||||
} else if (WorkingCopyFormat.ONE_DOT_THREE.equals(format)) {
|
||||
return SvnBundle.message("dialog.show.svn.map.table.version13.text");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static class LocationsCrawler implements SvnWCRootCrawler {
|
||||
private final SvnVcs17 myVcs;
|
||||
private final Map<String, File> myLocations;
|
||||
|
||||
public LocationsCrawler(SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
myLocations = new HashMap<String, File>();
|
||||
}
|
||||
|
||||
public String[] getLocations() {
|
||||
final Set<String> set = myLocations.keySet();
|
||||
return ArrayUtil.toStringArray(set);
|
||||
}
|
||||
|
||||
public Map<String, File> getLocationInfos() {
|
||||
return Collections.unmodifiableMap(myLocations);
|
||||
}
|
||||
|
||||
public void handleWorkingCopyRoot(File root, ProgressIndicator progress) {
|
||||
String oldText = null;
|
||||
if (progress != null) {
|
||||
oldText = progress.getText();
|
||||
progress.setText(SvnBundle.message("progress.text.discovering.location", root.getAbsolutePath()));
|
||||
}
|
||||
try {
|
||||
SVNWCClient wcClient = myVcs.createWCClient();
|
||||
SVNInfo info = wcClient.doInfo(root, SVNRevision.UNDEFINED);
|
||||
if (info != null && info.getURL() != null) {
|
||||
myLocations.put(info.getURL().toString(), info.getFile());
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
if (progress != null) {
|
||||
progress.setText(oldText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getRepositoryUUID(final SvnVcs17 vcs, final File file) {
|
||||
final SVNWCClient client = vcs.createWCClient();
|
||||
try {
|
||||
final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED);
|
||||
return (info == null) ? null : info.getRepositoryUUID();
|
||||
} catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getRepositoryUUID(final SvnVcs17 vcs, final SVNURL url) {
|
||||
final SVNWCClient client = vcs.createWCClient();
|
||||
try {
|
||||
final SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED);
|
||||
return (info == null) ? null : info.getRepositoryUUID();
|
||||
} catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNURL getRepositoryRoot(final SvnVcs17 vcs, final File file) {
|
||||
final SVNWCClient client = vcs.createWCClient();
|
||||
try {
|
||||
final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED);
|
||||
return (info == null) ? null : info.getRepositoryRootURL();
|
||||
} catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNURL getRepositoryRoot(final SvnVcs17 vcs, final String url) {
|
||||
try {
|
||||
return getRepositoryRoot(vcs, SVNURL.parseURIEncoded(url));
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNURL getRepositoryRoot(final SvnVcs17 vcs, final SVNURL url) {
|
||||
final SVNWCClient client = vcs.createWCClient();
|
||||
try {
|
||||
SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD);
|
||||
return (info == null) ? null : info.getRepositoryRootURL();
|
||||
} catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWorkingCopyRoot(final File file) {
|
||||
try {
|
||||
return SVNWCUtil.isWorkingCopyRoot(file);
|
||||
} catch (SVNException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getWorkingCopyRoot(final File inFile) {
|
||||
File file = inFile;
|
||||
while ((file != null) && (file.isFile() || (! file.exists()))) {
|
||||
file = file.getParentFile();
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File workingCopyRoot = null;
|
||||
try {
|
||||
workingCopyRoot = SVNWCUtil.getWorkingCopyRoot(file, true);
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
if (workingCopyRoot == null) {
|
||||
workingCopyRoot = getWcCopyRootIf17(file, null);
|
||||
}
|
||||
return workingCopyRoot;
|
||||
}
|
||||
|
||||
public static File fileFromUrl(final File baseDir, final String baseUrl, final String fullUrl) throws SVNException {
|
||||
assert fullUrl.startsWith(baseUrl);
|
||||
|
||||
final String part = fullUrl.substring(baseUrl.length()).replace('/', File.separatorChar).replace('\\', File.separatorChar);
|
||||
return new File(baseDir, part);
|
||||
}
|
||||
|
||||
public static VirtualFile getVirtualFile(final String filePath) {
|
||||
@NonNls final String path = VfsUtil.pathToUrl(filePath.replace(File.separatorChar, '/'));
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<VirtualFile>() {
|
||||
@Nullable
|
||||
public VirtualFile compute() {
|
||||
return VirtualFileManager.getInstance().findFileByUrl(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNURL getBranchForUrl(final SvnVcs17 vcs, final VirtualFile vcsRoot, final String urlPath) {
|
||||
final SvnBranchConfigurationNew configuration;
|
||||
try {
|
||||
final SVNURL url = SVNURL.parseURIEncoded(urlPath);
|
||||
configuration = SvnBranchConfigurationManager17.getInstance(vcs.getProject()).get(vcsRoot);
|
||||
return (configuration == null) ? null : configuration.getWorkingBranch(url);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
} catch (VcsException e1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getPathForProgress(final SVNEvent event) {
|
||||
if (event.getFile() != null) {
|
||||
return event.getFile().getName();
|
||||
}
|
||||
if (event.getURL() != null) {
|
||||
return event.getURL().toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile correctRoot(final Project project, final String path) {
|
||||
if (path.length() == 0) {
|
||||
// project root
|
||||
return project.getBaseDir();
|
||||
}
|
||||
return LocalFileSystem.getInstance().findFileByPath(path);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile correctRoot(final Project project, final VirtualFile file) {
|
||||
if (file.getPath().length() == 0) {
|
||||
// project root
|
||||
return project.getBaseDir();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public static boolean isOneDotFiveAvailable(final Project project, final RepositoryLocation location) {
|
||||
final SvnVcs17 vcs = SvnVcs17.getInstance(project);
|
||||
final List<WCInfo> infos = vcs.getAllWcInfos();
|
||||
|
||||
for (WCInfo info : infos) {
|
||||
if (! info.getFormat().supportsMergeInfo()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String url = info.getUrl().toString();
|
||||
if ((location != null) && (! location.toPresentableString().startsWith(url)) &&
|
||||
(! url.startsWith(location.toPresentableString()))) {
|
||||
continue;
|
||||
}
|
||||
if (! checkRepositoryVersion15(vcs, url)) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean checkRepositoryVersion15(final SvnVcs17 vcs, final String url) {
|
||||
SVNRepository repository = null;
|
||||
try {
|
||||
repository = vcs.createRepository(url);
|
||||
return repository.hasCapability(SVNCapability.MERGE_INFO);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
if (repository != null) {
|
||||
repository.closeSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SVNStatus getStatus(final SvnVcs17 vcs, final File file) {
|
||||
final SVNStatusClient statusClient = vcs.createStatusClient();
|
||||
try {
|
||||
return statusClient.doStatus(file, false);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static SVNDepth getDepth(final SvnVcs17 vcs, final File file) {
|
||||
final SVNWCClient client = vcs.createWCClient();
|
||||
try {
|
||||
final SVNInfo svnInfo = client.doInfo(file, SVNRevision.UNDEFINED);
|
||||
if (svnInfo != null) {
|
||||
return svnInfo.getDepth();
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
return SVNDepth.UNKNOWN;
|
||||
}
|
||||
|
||||
public static boolean seemsLikeVersionedDir(final VirtualFile file) {
|
||||
final String adminName = SVNFileUtil.getAdminDirectoryName();
|
||||
final VirtualFile child = file.findChild(adminName);
|
||||
return child != null && child.isDirectory();
|
||||
}
|
||||
|
||||
public static boolean isAdminDirectory(final VirtualFile file) {
|
||||
return isAdminDirectory(file.getParent(), file.getName());
|
||||
}
|
||||
|
||||
public static boolean isAdminDirectory(File parent, final String name) {
|
||||
if (name.equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
if (parent != null) {
|
||||
if (parent.getName().equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
parent = parent.getParentFile();
|
||||
if (parent != null && parent.getName().equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isAdminDirectory(VirtualFile parent, String name) {
|
||||
// never allow to delete admin directories by themselves (this can happen during LVCS undo,
|
||||
// which deletes created directories from bottom to top)
|
||||
if (name.equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
if (parent != null) {
|
||||
if (parent.getName().equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
if (parent != null && parent.getName().equals(SVN_ADMIN_DIR_NAME)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SVNURL getUrl(final File file) {
|
||||
SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
|
||||
try {
|
||||
wcAccess.probeOpen(file, false, 0);
|
||||
SVNEntry entry = wcAccess.getVersionedEntry(file, false);
|
||||
return entry.getSVNURL();
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
} finally {
|
||||
try {
|
||||
wcAccess.close();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean doesRepositorySupportMergeinfo(final SvnVcs17 vcs, final SVNURL url) {
|
||||
SVNRepository repository = null;
|
||||
try {
|
||||
repository = vcs.createRepository(url);
|
||||
return repository.hasCapability(SVNCapability.MERGE_INFO);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (repository != null) {
|
||||
repository.closeSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean remoteFolderIsEmpty(final SvnVcs17 vcs, final String url) throws SVNException {
|
||||
SVNRepository repository = null;
|
||||
try {
|
||||
repository = vcs.createRepository(url);
|
||||
final Ref<Boolean> result = new Ref<Boolean>(true);
|
||||
repository.getDir("", -1, null, new ISVNDirEntryHandler() {
|
||||
public void handleDirEntry(final SVNDirEntry dirEntry) throws SVNException {
|
||||
if (dirEntry != null) {
|
||||
result.set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
} finally {
|
||||
if (repository != null) {
|
||||
repository.closeSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] decode(final Charset charset, final byte[] buffer) {
|
||||
if (charset != null && ! CharsetToolkit.UTF8_CHARSET.equals(charset)) {
|
||||
return CharsetToolkit.UTF8_CHARSET.encode(charset.decode(ByteBuffer.wrap(buffer))).array();
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getWcCopyRootIf17(final File file, @Nullable final File upperBound) {
|
||||
File current = file;
|
||||
while (current != null) {
|
||||
try {
|
||||
final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(current, false);
|
||||
if (SvnWcGeneration.V17.equals(svnWcGeneration)) return current;
|
||||
if (SvnWcGeneration.V16.equals(svnWcGeneration)) return null;
|
||||
if (upperBound != null && upperBound.equals(current)) return null;
|
||||
current = current.getParentFile();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean is17CopyPart(final File file) {
|
||||
try {
|
||||
return SvnWcGeneration.V17.equals(SvnOperationFactory.detectWcGeneration(file, true));
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author alex
|
||||
*/
|
||||
public interface SvnWCRootCrawler {
|
||||
void handleWorkingCopyRoot(File root, ProgressIndicator progress);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
public class SvnWorkingCopyFormatHolder {
|
||||
private static final ThreadLocal<WorkingCopyFormat> myPresetFormat = new ThreadLocal<WorkingCopyFormat>();
|
||||
|
||||
private SvnWorkingCopyFormatHolder() {
|
||||
}
|
||||
|
||||
public static WorkingCopyFormat getPresetFormat() {
|
||||
return myPresetFormat.get();
|
||||
}
|
||||
|
||||
public static void setPresetFormat(final WorkingCopyFormat value) {
|
||||
myPresetFormat.set(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2010 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentI;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentFactory;
|
||||
import org.jetbrains.idea.svn17.dialogs.CopiesPanel;
|
||||
|
||||
public class WorkingCopiesContent {
|
||||
private final SvnVcs17 myVcs;
|
||||
private Content myShownContent;
|
||||
|
||||
public WorkingCopiesContent(SvnVcs17 vcs) {
|
||||
myVcs = vcs;
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
final ChangesViewContentI cvcm = ChangesViewContentManager.getInstance(myVcs.getProject());
|
||||
final ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
|
||||
|
||||
final CopiesPanel copiesPanel = new CopiesPanel(myVcs.getProject());
|
||||
myShownContent = contentFactory.createContent(copiesPanel.getComponent(), SvnBundle.message("dialog.show.svn.map.title"), true);
|
||||
myShownContent.setCloseable(false);
|
||||
cvcm.addContent(myShownContent);
|
||||
myShownContent.setPreferredFocusableComponent(copiesPanel.getPreferredFocusedComponent());
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
if (myShownContent != null) {
|
||||
final ChangesViewContentI cvcm = ChangesViewContentManager.getInstance(myVcs.getProject());
|
||||
cvcm.removeContent(myShownContent);
|
||||
myShownContent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
import org.tmatesoft.svn.core.SVNURL;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class WorkingCopy {
|
||||
private final File myFile;
|
||||
private final SVNURL myUrl;
|
||||
|
||||
public WorkingCopy(File file, SVNURL url) {
|
||||
myFile = file;
|
||||
myUrl = url;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
public SVNURL getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
WorkingCopy that = (WorkingCopy)o;
|
||||
|
||||
if (!myFile.equals(that.myFile)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myFile.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.svn17;
|
||||
|
||||
/**
|
||||
* since not all constants are available from svnkit & constants are fixed
|
||||
*/
|
||||
public enum WorkingCopyFormat {
|
||||
ONE_DOT_THREE(4, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version13.text")),
|
||||
ONE_DOT_FOUR(8, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version14.text")),
|
||||
ONE_DOT_FIVE(9, true, true, false, SvnBundle.message("dialog.show.svn.map.table.version15.text")),
|
||||
ONE_DOT_SIX(10, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version16.text")),
|
||||
ONE_DOT_SEVEN(12, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version17.text")),
|
||||
UNKNOWN(0, false, false, false, "unknown");
|
||||
|
||||
private final int myFormat;
|
||||
private final boolean myChangelistSupport;
|
||||
private final boolean myMergeInfoSupport;
|
||||
private final boolean myTreeConflictSupport;
|
||||
private final String myName;
|
||||
|
||||
private WorkingCopyFormat(final int format, boolean changelistSupport, boolean mergeInfoSupport, boolean treeConflictSupport, String name) {
|
||||
myFormat = format;
|
||||
myChangelistSupport = changelistSupport;
|
||||
myMergeInfoSupport = mergeInfoSupport;
|
||||
myTreeConflictSupport = treeConflictSupport;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public boolean supportsChangelists() {
|
||||
return myChangelistSupport;
|
||||
}
|
||||
|
||||
public boolean supportsMergeInfo() {
|
||||
return myMergeInfoSupport;
|
||||
}
|
||||
|
||||
public boolean supportsTreeConflicts() {
|
||||
return myTreeConflictSupport;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public static WorkingCopyFormat getInstance(final int value) {
|
||||
if (ONE_DOT_FIVE.getFormat() == value) {
|
||||
return ONE_DOT_FIVE;
|
||||
} else if (ONE_DOT_FOUR.getFormat() == value) {
|
||||
return ONE_DOT_FOUR;
|
||||
} else if (ONE_DOT_THREE.getFormat() == value) {
|
||||
return ONE_DOT_THREE;
|
||||
} else if (ONE_DOT_SIX.getFormat() == value) {
|
||||
return ONE_DOT_SIX;
|
||||
} else if (ONE_DOT_SEVEN.getFormat() == value) {
|
||||
return ONE_DOT_SEVEN;
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public static WorkingCopyFormat getInstance(final String updateOption) {
|
||||
if (SvnConfiguration17.UPGRADE_AUTO_17.equals(updateOption)) {
|
||||
return ONE_DOT_SEVEN;
|
||||
} else if (SvnConfiguration17.UPGRADE_AUTO_16.equals(updateOption)) {
|
||||
return ONE_DOT_SIX;
|
||||
} else if (SvnConfiguration17.UPGRADE_AUTO_15.equals(updateOption)) {
|
||||
return ONE_DOT_FIVE;
|
||||
} else if (SvnConfiguration17.UPGRADE_AUTO.equals(updateOption)) {
|
||||
return ONE_DOT_FOUR;
|
||||
}
|
||||
return ONE_DOT_THREE;
|
||||
}
|
||||
|
||||
public int getFormat() {
|
||||
return myFormat;
|
||||
}
|
||||
|
||||
public String getOption() {
|
||||
if (ONE_DOT_SEVEN.equals(this)) {
|
||||
return SvnConfiguration17.UPGRADE_AUTO_17;
|
||||
} else if (ONE_DOT_SIX.equals(this)) {
|
||||
return SvnConfiguration17.UPGRADE_AUTO_16;
|
||||
} else if (ONE_DOT_FIVE.equals(this)) {
|
||||
return SvnConfiguration17.UPGRADE_AUTO_15;
|
||||
} else if (ONE_DOT_FOUR.equals(this)) {
|
||||
return SvnConfiguration17.UPGRADE_AUTO;
|
||||
}
|
||||
return SvnConfiguration17.UPGRADE_NONE;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user