summaryrefslogtreecommitdiff
path: root/plugins/svn4idea
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-11-12 10:41:52 -0800
committerTor Norbye <tnorbye@google.com>2013-11-12 10:42:01 -0800
commit9c6f3112ffe942e4bb0b5d5d8476ce7014499650 (patch)
treea0a1a2817c17cddc428e1faf8dd7754ab593c0dc /plugins/svn4idea
parentf88d3e15cd8228cba4070811da68d8ad54d81fd7 (diff)
downloadidea-9c6f3112ffe942e4bb0b5d5d8476ce7014499650.tar.gz
Snapshot 205707dc11cdd6508ae84db85d104f834028fd65 from idea/132.1045 of git://git.jetbrains.org/idea/community.git
205707d: support abbreviations in Search Everywhere 9eeb98a: NPE fix f701598: AA painting for shortcuts 9636e23: add abbreviations d1f7c58: IDEA-116296 Search match looks terrible under Retina 8bc5adc: AIOOBE f92fa41: IDEA-116194 "Generate equals() and hashcode()" for final classes should disable "accept subclasses" variant ec773fc: CCE 9a208ab: selected completion item should be the first or second visible (IDEA-115199) be542d6: linear-time filterByDumbAwareness 83273e5: faster next/prev occurrence action in the console (IDEA-115163) d684469: LanguageConsole: shutdown printXXX fiesta. Everyone is advised to use ConsoleView API the right way. 480215a: Merge branch 'master' of git.labs.intellij.net:idea/community c85aae4: https://android-review.googlesource.com/69716 76daf2e: Heroku integration - show log on redeploy c567431: Jediterm updated (PY-11368). 5d325de: Accept only terminal tabs on DnD. a1d5cd4: Merge remote-tracking branch 'origin/master' 0a3bcdb: Jediterm updated. 218607a8: Terminal: support presentation mode. ea6fd6f: switch on console-content-type highlighting in all language consoles e824117: Quick fix for RefParserTest 450ecea: suggest scrambled classes on second completion 7ba82d9: NPE fixed 525a30d: cleanup 2fa314d: don't display "Loading spellchecker dictionaries" in status bar (IDEA-115130) 276a47a: don't suggest scrambled classes in autopopup (IDEA-115199) b4a4b99: temporary fix for layouts of small IDEs 02e07e1: [log] Move SimpleHash from vcs-log-graph to vcs-log-impl f7b1796: [log] Hash -> int in Graph 0c4d0bb: [log] Don't call new VcsRefImpl() directly, use the factory 4c1c1c2: [log] Memory consumption: Hash -> int. Take 1 2e36939: Improvement from Roman Shevchenko to be compatible with Ubuntu 13.10. b6edb35: Show pin icon in pinned Find Usages tabs c143cee: IDEA-110064 JSF 2.2: Pass-through elements: if upper-case symbols are used instead of default 'jsf' namespace prefix, attributes are red-highlihted 3a69458: added actions 'mark/unmark as generated sources root' to popup menu bdfc48c: Use maven3 importer by default. d9417b6: Merge remote-tracking branch 'origin/master' 5b526fc: Add pty libs to pycharm community build. c912c67: add HowTo 6d940b1: depend on PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT if the file cannot be resolved yet 7c63c25: platform: jayatana patched to support Ubuntu 13.10 (sources only) 59622ee: IDEA-116276 Console font is small in Presentation mode 6863abc: IDEA-115889 Framework toolwindows: support scope-based file colors for items ac0f8ab: obtaining framework libraries from app server: download libraries list asynchronously from server 185804e: refactor supported root type checking according to CR-IC-3056 6b085fe: formatter removes spaces in import statement parentheses (PY-11359) b04030e: Show pin icon in pinned Find Usages tabs 90ea6d7: do not disable empty frameworks page if no templates available bb55e29: platform: jayatana sources attached d1911f7: platform: Ubuntu app menu loading code extracted and corrected 897738a: Cleanup (deprecated code) 56e41fb: Check Grails SDK in background thread, not in the AWT. +review CR-IU @gromopert fd2b6b3: IDEA-115074 New Project Wizard: Grails: grails-specific settings are missing a69a88a: spi: decline abstract classes, suggest all available inheritors (IDEA-115502) eeaee1e: SIOOBE 6cd3cb9: Fix spelling 5f4c814: IDEA-102413 (pointless assertion dropped) dc455bd: Cleanup (arrangement, formatting) 44590dc: IDEA-25934 Maven: Webapp resources filtering store web resources configuration. 6e65f2b: IDEA-25934 Maven: Webapp resources filtering store web resources configuration. df137ae: DOM stubs: namespace key index 046e455: Merge remote-tracking branch 'origin/master' 0681517: testdata fixed dd63221: IDEA-116168 Action creation does not escape special chars in plugin.xml 48fa01e: restore plugin description d34d829: new project wizard: remote templates 389db71: methods renamed b07e674: prefer non-qualified xml completion variants (IDEA-115355) add165a: IDEA-116144 Opening build.gradle of android project fails d524a84: refixed IDEA-111753 to remove unnecessary dependency on debugger b8df146: show usages from generated code in separate group (IDEA-97579) 034f42b: removed obsolete 'remote-server-util' module from installation, added new module to git plugin installation c8deccf: download libraries in parallel (IDEA-88561) 674de91: our LinkedHashMap: added methods to obtain last added key/value 43aced8: Restore context menu after DnD back to Terminal View. b6987d3: Merge remote-tracking branch 'origin/master' c147027: Fix: terminal tab doesn't save name change after DnD. 495bda4: JediTerm update to version 1.0 46667e2: Fix closing tab on session end. Fix popup for editor terminal tabs. fdd3e70: Fix potential NPE. 9ea940a: [git] Fix refresh notification after changing non-active branch hashes 34b357c: more console folding by default d21cf01: Fix memory leak. 1dcfd64: Fix removing terminal tabs on drag'n'drop. 29a4f60: add accessOrder parameter to our LinkedHashMap e0ff96d: DockableEditorTabbedContainer shouldn't return root pane as accept area as it makes impossible to add any other dockable container. It is better to return root pane in the special fallback method after we checked all containers. 4b22045: Terminal tabs: drag'n'drop to editor and back implemented. 6ac9ae9: DockableEditor doesn't need EditorWindow reference. 73f7ab5: [log] IDEA-115980 Don't show Git actions if there are no Git roots 7964385: [log] "Go To Commit" action c647083: [log] Extract the popup text field used for user completion 7e9497a: Merge remote-tracking branch 'origin/master' 0eb8a6f: [log] Fix hidden graph because of the date filter existance 95d5d5b: [log] IDEA-116022 Implement Structure filter for VCS Log & Git 4989fa1: [vcs] VcsStructureChooser: remove dependency on the AbstractVcs. 278cd62: [log] move structure filter implementation to vcs-log-impl 9b5b1c2: Github: change search request parameter a543347: IDEA-115330 Incorrect "condition is always false" 0b85cc1: trying to make project opening progress information more meaningful (IDEA-115130) 35af155: Don't display empty panel if there are no moreMessage in the dialog 41592ca: [vcs] IDEA-116036 Pressing Escape in Commit/TODO dialog performs commit 7c5ba53: [log] Fix IDEA-115676 once again 8fb8d34: [log] IDEA-116056 Display commit time in details if different from author time 9b6d291: [log] IDEA-116022 Add filter by date c49b45b: only suppress eager psi creation when there were stubs in the file f815aa9: our LinkedHashMap clients aren't necessarily aware that it updates its ordering on every get. Let clients specify if they need this feature (IDEA-116222) 6fcd19c: return not-null MODULE_CONTEXT data only for single content roots (IDEA-115422) 0af49e6: fix two psi elements per one ast element in stub-ast switch: psi1 is taken from stub psi2 is eagerly created during chameleon parsing another thread gets the ast when some psi1 parent is already switched and psi1 is not, it walks down the ast and gets psi2 fcfef16: remove big JI sign 2ad7bd2: support for <shortcut> cd74ff8: IDEA-116206 59b556f: set transparency 20% 152e772: fix missing help button b8f59ef: add getLanguage() method 25dece1: IDEA-110540 ("String concat (+) and super.toString()" template adds "+ super.toString()" even if no super) 35c07da: new inference: reject isExact for no constructor parameterized class 5fafbd5: EA-51725 - NPE: IntroduceVariableBase.replace 22cf8de: ignore anonymous classes when generating constructors EA-51713 - assert: CreateConstructorMatchingSuperFix$.run 1735391: getWidget method fcb4970: attempt to fix IDEA-116128 LiveEdit doesn't work correctly for JSP files 36e4932: continue "ability to return list of URLs" — isConfigurationFromContext d67f88c: Cleanup (formatting) 3112d12: reliably check if a task for debugger manager thread was interrupted 201c7b5: IDEA-75717 ("Referenced checked for null not used inside if" false positive) 795357c: do not suppress file-level inspections 4745efc: continue "ability to return list of URLs" IDEA-115787 43216f8: IDEA-115787 Better resolvement for JSF page URLs 2e6db86: IDEA-100279 ChooseComponentsToExportDialog 72ee12c: fix warning "mac file equals" 19576b2: overrides, cleanup 0a15306: IDEA-100279 git init b596340: IDEA-100279 xml editor location dialog 3c0f6cd: IDEA-100279 copyright plugin b7c6e4c: overrides e9e6eb2: 'Download library' refactored a little 946216e: IDEA-116197 (filter improvements) 9439744: EA-51425 - ISE: MavenUtil.resolveSuperPomFile add assertion. 9c38499: EA-51325 - assert: MavenIndices.createNewDir 9346755: don't log Connection reset by peer cfb11fa: cleanup 038e39d: IDEA-114461 Structure tool window: Jump to Source (F4) does not move focus to Editor ed4794e: VcsRootDetector and RootErrorsFinder tests updated c196ab3: Remove unnecessary check and param from HgRepositoryImpl b486fcb: template actions are now injection aware 773f5f0: IDEA-102454 Parameter Info: TAB/Shift-TAB and editing does not work in language injected fragment 3b34a0b: IDEA-49273 Injected language: parameter info tooltip disappears on moving caret 7afa57d: move indexer to indexing-impl 4ab17a0: don't shift text range if the element has no last child (PY-11344) 9e3bbe9: don't show "inspect test source" checkbox in PyCharm (PY-1187) ac7f1b2: IDEA-113483 (action fixed to select directories too) 7bd9931: Emmet: extract SurroundWithEmmetAction 625e81b: don't show "production" and "test" scopes in predefined scopes if current product doesn't support test source roots (PY-7324) f01a713: grouping by directory uses project-relative paths (PY-11176); rename the action from "Group by package" to "Group by directory" in platform-based IDEs be45c85: move GeneralFormatterTest to platform-tests; fix NPE in DocumentImpl when running standalone GeneralFormatterTest 4d22f5e: DirectoryIndex: don't include roots from content to projectExcludeRoots set, update projectExcludeRoots on VFS change 02f7305: Merge branch 'master' of git.labs.intellij.net:idea/community 7994da2: External System: test fix Related task: IDEA-79466 gradle support should generate web module configuration e3cfba1: IDEA-116126 - NoClassDefFound on attempt to deploy to heroku 630eacf: Merge remote-tracking branch 'origin/master' a902c4e: testdata fixed db0433c: fix NPE — final class variable is not yet initialized — we must not open connection until debug process class is not constructed. dd2d5f6: platform: ensure event file validity on dropping symlink target eaeed33: platform: better pairing of before/after VFS events 97aec30: Cleanup (formatting) 017646f: remove dead code, cleanup 2181005: more templates ab315c8: new project wizard: template description & count e789a57: External system: adding TEST_GENERATED source type to ExternalSystemSourceType 62eeca9: new project wizard: adding project templates 25e633c: SimpleColoredComponent: builder style 84c2eb6: ColoredListCellRenderer parameterized 3c567ba: cleanup ab15886: cleanup aaad70d: cleanup 81c7d30: update Key.findKeyByName usages due to API changes 41ca0a4: CCE aware API fe3700f: java call hierarchy extension 51c76a3: Make view meta model extendable e17daa4: unused methods with strange names deprecated 4910498: service replaced by utility methods d0fd16f: faster for simple cases 3dd6919: fix CSS completion tests: if the reference starts at completion start location, we do need to overwrite it when Tab is pressed 22c1ef9: Gradle: update to Gradle 1.9-rc-3 7a38323: Pty4j updated. 29ac873: IDEA-97390 Java Debugger: View Text action shows white on white [2] 1c329ac: Merge branch 'master' of git.labs.intellij.net:idea/community 0c60dd9: IDEA-86998 Evaluate expression mixes colorschemas when displaying injected code ce6fbd9: IDEA-97390 Java Debugger: View Text action shows white on white a50bd7e: Merge branch 'master' of git.labs.intellij.net:idea/community 8de20e2: remote servers - headers cleanup c5e1cf7: don't reformat mock variable during control flow building 8e11281: don't walk module src roots in search for .class file source (IDEA-116085) 992d740: cache expected names (IDEA-116085) 10976b3: walk library src roots once when searching for class sources (IDEA-116085) dfc71fc: fix java pull up refactoring! 4af2a83: Merge remote-tracking branch 'origin/master' a818922: javadoc: include in classpath only libraries from modules which participate in the scope (IDEA-116083) 38e2991: new inference: do not use nested call args to infer on the top level 465762a: new inference: reject multiple eq bounds d84a0a0: Darcula eats almost all EDT cpu time fe23143: IDEA-94922 (Report negatively named boolean variables and suggest to perform 'Invert Boolean' for them) f637ac6: fix description 9005acd: common "invert boolean" quickfix 9a5bfa9: add #loc's dd94fc6: fix "No dependencies provided which causes CachedValue to be never recalculated again." e4cce36: java.lang.IllegalThreadStateException additional handling 1249362: disposed check 0495c47: cleanup 25fc653: extra inspections 8850957: IDEA-101405 Call hierarchy support for Groovy 3026341: hierarchy package deb52f5: Flat & round stripe buttons (Internal Mode only) v.3, colors improvement d903511: IDEA-116139 Workaround NPE fix 8fccc30: avoid assertion on file path completion (EA-51068) fdb9f6e: ctrl+w shouldn't choke on unclosed argument lists (EA-51589) 1de20e6: don't inc modification counter on first load of gant/gradle settings 8a9c177: IDEA-25934 Maven: Webapp resources filtering store web resource configuration. 9553c1a: catch all exceptions that may influence VM attach process aa8a8e8: IDEA-116146 Search everywhere has small font in Presentation mode 9c7d5d5: #WEB-8915 fixed 5d96196: dfa: flush resource variables when leaving try block 15c0fd6: jsr166e.jar included into standalone jps distribution edbde43: generics: bounds check should stop expanding nested wildcards up to 2nd level d991c73: fix invalid file assertion aae4c5a: IDEA-116049 Mercurial log problem with Mac default locale (x_MacRoman) 08a6b0c: Unnecessary encoding argument in new hg log removed. 5cd75d1: style 5a365fd: fix BooleanParameterInspectionTest 4e2e6ca: [log] IDEA-115966 Show HAND cursor over branch arrows 7793ca6: [log] Collect user information from the whole log 4e8c466: [log] Completion in filter by user bc4c9f8: [log] intern VcsUsers. 0505705: [log] Encapsulate author & committer into VcsUser 1fb280e: [log] Let VcsLogObjectsFactory be project service & depend on VcsLogManager 2f2f008: Gradle: add Tooling API extra models support. Related task: IDEA-79466 gradle support should generate web module configuration 3c9aa6d: convert EventLogCategory to abstract class 0804cb1: html5 char entities for fragments 0e50db9: #IDEA-116106 fixed 483a5d1: enable entities validation for html5 #WEB-7053 fixed 962e050: generated entities for html 5 chars, use it in resolve and completion b57823a: Merge remote-tracking branch 'origin/master' da8e5d0: we must add "http://" prefix if specified path is not absolute 6bb2810: small lens mode fix 88caaf7: Merge remote-tracking branch 'origin/master' 4268072: IDEA-116125 extra gutter in presentation mode 6d03a86: Eliminated dependencies on pthread, glib rec mutex synchronization. A crash fixed. b5f05f4: Quick fix for not Unity window managers. Should be moved into linux-specific code. fe27876: WI-14476 When hovering over variable, Expression Evaluation tooltip disappears before I can click the + icon (cherry picked from commit 3034e98) 202e2ae: Cleanup (test) a5960af: java: no need to check package prefix for annotations on ref adjustment ab262e2: Cleanup (test) 5b2a86b: IDEA-89720 Preview usages: "select usages to preview" should be shown at the center of panel 7b82bf1: IDEA-116119 Darcula: links are hardly visible on warnings d2a2cd9: don't hide run configuration type if there are only one irrelevant type (IDEA-116046) 15e08d4: javadoc corrected 5575eb1: hide 'deploy to cloud' run configurations if corresponding cloud isn't configured (IDEA-116046) 3b3c221: WEB-9876 Fuzzy search is still colliding with completion 50bd840: Spock method should be a GrMethod. 5364513: exception-safe rendering 544a580: thread assertion fix bc4c101: fix NPEs 56940f1: a way to increase dismiss delay 9aee54e: framework version from existing library 37f430f: removing borders automatically 19a21fd: new "Non-varargs method overrides varargs method" inspection e82e54d: improve description 31fedec: New in 13 0fbffa1: fixed downloading client libraries from modal dialog (IDEA-115975) 5db09f5: CCE from android step fixed cded14f: IDEA-115064 New Project Wizard: Spring page looks bad: preselected frameworks e6b1f8e: fix NPE (request status) 8bba7c9: IDEA-115076 Groovy: New Project Wizard: IAE at DialogWrapperPeerFactoryImpl.createPeer() on 'Create Groovy Library' 5a47ef8: app server editor: don't show 'change version' button for app server library f510156: IDEA-115398 New Project Wizard: libraries downloading doesn't work 3d251be: event log category EP 7d76939: Take shortcuts for next tab and prev tabs from keymap. be19e2e: Next tab and Previous tab actions. 67310ba: Null class name tolerated db170d7: Fixed text shaking on tab name editing. bd3c4bc: Some cleanup. b27ba6e: IDEA-112596 SQL: MySQL uncomment doesn't work with "--" a67dac8: IDEA-115954 lens mode warning annotation bubbles overlap text on retina b6c179c: IDEA-93733 Double line above editor tabs 2c91f79: EA-51491 - assert: DocumentImpl.createRangeMarker 1743e7b: EA-51650 - assert: JavaDocInfoGenerator.getDocComment 16712b8: Todo f9d2c43: Cleanup (formatting) 38f058d: failing test for PY-10319 dd3f3fa: rename some methods and cleanup code to make logic clearer aa885ea: report missing identifier after 'as' (PY-9853) 52efcb5: only allow single expression after 'in'; tweak error recovery when waiting for colon (PY-9561) 7f8dc3d: change default match-from-start to false bfb1819: EA-51669 (unneeded augmentation avoided) b27e492: platform: extension point declaration moved to correct .xml 4d9e686: sourcemaps: ability to resolve sources relative to generated file 40e08dc: Fix the size changing of text field for terminal tabs. 62223eb: Merge remote-tracking branch 'origin/master' 6c84d33: take synchronized statements into account when mapping local variable names to slots 4e560b6: allow to view hidden items in 'New Run Configuration' popup (IDEA-116046) 37caefe: IDEA-72889 (CodeStyle inspection to check tabs instead of spaces in file) f345cfd: EA-51469: do not call GemManager.updateGemset(Module) with null e27287d: ShowSettingUtil: selecting configurable by class is fixed b9f0e95: new inference: infer recursively for conditional expression 646aea3: new inference: avoid self bounds when possible a2ad6fd: new inference: accept captured wildcard opening during subtype constraint reduction 66462d0: remove incorrect copyright messages c3c03a0: don't set default cursor if empty text is invisible 4f009e8: IDEA-115398 New Project Wizard: libraries downloading doesn't work 3607191: Merge remote-tracking branch 'origin/master' a95509a: extracted method to get/set 'for generated source' option via API 7b00b8f: hide Groovy run configuration if there are no groovy files in project (IDEA-116046) 89f2a76: Minor VFS optimization (cleanup) 0defb40: less spam in the logs when there's PSI/document inconsistency during reference search (IDEA-115950) 29427e7: added service to quickly find modules by module type; hide DevKit and J2ME run configurations if there are no corresponding modules (IDEA-116046) d031ebc: hide Python run configurations if they are irrelevant (IDEA-116046) 75ca45a: IDEA-116000 Error message shown if hg root marked as git e9b3a8c: style 24f91c2: IDEA-115474 Maven Dependency template broken in latest Idea Cardea 26b5659: added API to hide irrelevant run configuration types from 'New' popup in 'Edit Configurations' dialog (IDEA-116046) 5b6b259: Merge remote-tracking branch 'origin/master' 0525b10: Revert the change. 4f9d3f0: Disable formatter ranges in formatter off/on tags [CR-IC-2916] f760c44: IDEA-36685: Provide better 'no matching constructor' warnings where possible 915fb35a: new overload resolution: testdata 3546317: new overload resolution 971909a: method refs: exact tweaks f6932ac: Merge remote-tracking branch 'origin/master' c22e14c: JediTerm jar updated. 08eed1d: Merge remote-tracking branch 'origin/master' 5ff6e1a: Merge remote-tracking branch 'origin/master' feec183: Pty4j with debug info. 08c90e8: Minor VFS optimization 53a81a0: Cleanup (formatting) dc52633: EA-50578 - assert: TextRange.<init> b532d92: Merge remote-tracking branch 'origin/master' aa20e7d: status bar should have a height at least of an icon, even before any icons appear, to prevent unnecessary blinking (IDEA-114453) 1e0e31e: IDEA-112982 Status bar starts with bad layout before project is fully loaded default min height was 1 which made BoxLayout center-align everything along the top border resulting in 2x less memory indicator height 5fdc8f8: Merge branch 'svn_18_2' cc6dd17: svn: Fixed destroy for process under terminal 9826ae7: external system: EA-51656, check for disposable project components added 7337a62: external system: EA-51656, check for disposable project components added ea5159b: IDEA-116001 Incorrect behavior of root scanner in case non hg project marked as hg fixed 2186112: Merge remote-tracking branch 'origin/master' 9f02f7e: don't generate icons for IntelliJ laf 0f252a9: IDEA-90751 Scope tabs coloring does not affect hidden tabs pop-up ab0e88a: cleanup dead code 79bf40e: IDEA-114608 breakpoints dialog: add panel must be at top d9b94c5: new icons: vendors & sql structure view 5b4b9a7: svn: Do not read from error stream for process under terminal ca6a8ac: drop command wrapper 5617a42: use correct date format in command to fix reverting changes on file with a sticky date afbef4d: new inference: mark List::get as inexact 4fde439: EA-51621 - IOE: CheckUtil.checkWritable eb79b67: EA-51643 - assert: DataManagerImpl$MyDataContext.getData e1b69a4: new inference: exact method reference: decline constructor with parameter with type parameter of class 664ee85: improve parser recovery if keyword is used as function or class name (PY-8319) 5d6bac5: improve parser recovery if keyword is used as named parameter (PY-8318) ce1ff5d: if we have only one import candidate, show its name instead of "import this name" (PY-8067) 27c5fbb: Visual Studio keymap maps Shift+F1 to both QuickJavaDoc and ExternalJavaDoc (PY-7291) baaf551: rename file when renaming class if file name equals lowercased class name (PY-7155) f52709b: tweak decorator parsing so that following line comment is outside the text range of PyDecorator (PY-5912) a61112a: don't overwrite reference by Tab if it starts exactly after reference being completed (PY-6095) 12249d1: tab completion for keyword arguments overwrites the = sign (PY-1337( a351f53: highlight only the last line of string literal when triple quotes are unclosed (PY-1780); allow running StringLiteralQuotesAnnotator in dumb mode 1bf4336: consistent behavior of PyFunction.getContainingClass() in stub-based and non-stub-based cases (PY-1448) 36c20c2: fix caret position after pressing Enter in Python line comment e55c85f: fix HtmlCompletionTest.testDotTypeWhileActiveLookupInFileReference a3e89bc: IntelliLang PatternValidator: class parsing errors should not fail the build if the class is not going to be instrumented by the validator. Covered 2 more cases when this check was not performed (IDEA-115189 IntelliLang Pattern Validator: Class not found) 6f7b23e: Merge remote-tracking branch 'origin/master' c5d7ccd: Merge remote-tracking branch 'origin/master' 946d9ab: svn: terminal: Implemented handling of "unknown host" prompt for ssh f1e1ceb: IDEA-113191 Used "write" access to sqlite db and try to access db several times if failed b95367c: svn: Do not handle auth errors when command is finished if in terminal mode e306801: svn: terminal: Added separate logging for status command output (as there are some issues with terminal output parsing) f22a4ed: svn: terminal: Implemented cancelling authentication prompts 4e7c774: svn: terminal: Treat stdout lines with svn errors as stderr lines a48733d: svn: Fixed default focused element for credentials dialog opening (password is focused if username is disabled) aac45e5: svn: Implemented password prompts for ssh authentication through terminal b8768d1: svn: Implemented basic svn+ssh authentication using terminal (under svn.use.terminal registry key) 13a217b: svn: Refactored CommandExecutor - ability to write to process input stream, small changes for inheritors e9ccca6: svn: Moved setting "non-interactive" mode when command executor is created 4092ffa: svn: Added command logging in for non-zero exit code 8441324: Tab name length is limited by 50 in jediterm library. 1c63154: Use JB tabs in terminal(PY-10609). Pass disposable to terminal widget. 2ba2163: Extract method that sets content to the holder. 9c5a392: NPE (IDEA-115607). Change-Id: I83d19d7826b59dbc1d782247b78553b4632e7635
Diffstat (limited to 'plugins/svn4idea')
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java74
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java6
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java60
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java1
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java33
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/InteractiveCommandListener.java26
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java5
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java104
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java153
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java164
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSHDialog.java13
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleCredentialsDialog.java22
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ToBeMergedDialog.java2
-rw-r--r--plugins/svn4idea/svn4idea.iml3
14 files changed, 634 insertions, 32 deletions
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java
index 073bf57a48e3..ce734fd683fd 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.svn;
+import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
@@ -25,11 +26,13 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangesUtil;
+import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -57,6 +60,7 @@ import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
+import java.nio.channels.NonWritableChannelException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -369,30 +373,34 @@ public class SvnUtil {
*/
@NotNull
public static WorkingCopyFormat getFormat(final File path) {
- int format = 0;
+ WorkingCopyFormat result = null;
File dbFile = resolveDatabase(path);
if (dbFile != null) {
- SqlJetDb db = null;
+ result = FileUtilRt.doIOOperation(new WorkingCopyFormatOperation(dbFile));
+
+ if (result == null) {
+ notifyDatabaseError();
+ }
+ }
+
+ return result != null ? result : WorkingCopyFormat.UNKNOWN;
+ }
+
+ private static void close(@Nullable SqlJetDb db) {
+ if (db != null) {
try {
- db = SqlJetDb.open(dbFile, false);
- format = db.getOptions().getUserVersion();
+ db.close();
}
catch (SqlJetException e) {
- LOG.error(e);
- } finally {
- if (db != null) {
- try {
- db.close();
- }
- catch (SqlJetException e) {
- LOG.error(e);
- }
- }
+ notifyDatabaseError();
}
}
+ }
- return WorkingCopyFormat.getInstance(format);
+ private static void notifyDatabaseError() {
+ VcsBalloonProblemNotifier.NOTIFICATION_GROUP
+ .createNotification("Some errors occurred while accessing svn working copy database.", NotificationType.ERROR).notify(null);
}
private static File resolveDatabase(final File path) {
@@ -803,4 +811,40 @@ public class SvnUtil {
// thrown when getting info from repository for non-existent item - like HEAD revision for deleted file
SVNErrorCode.ILLEGAL_TARGET.equals(code);
}
+
+ private static class WorkingCopyFormatOperation implements FileUtilRt.RepeatableIOOperation<WorkingCopyFormat, RuntimeException> {
+ @NotNull private final File myDbFile;
+
+ public WorkingCopyFormatOperation(@NotNull File dbFile) {
+ myDbFile = dbFile;
+ }
+
+ @Nullable
+ @Override
+ public WorkingCopyFormat execute(boolean lastAttempt) {
+ // TODO: rewrite it using sqlite jdbc driver
+ SqlJetDb db = null;
+ WorkingCopyFormat result = null;
+ try {
+ // "write" access is requested here for now as workaround - see some details
+ // in https://code.google.com/p/sqljet/issues/detail?id=25 and http://issues.tmatesoft.com/issue/SVNKIT-418.
+ // BUSY error is currently handled same way as others.
+ db = SqlJetDb.open(myDbFile, true);
+ result = WorkingCopyFormat.getInstance(db.getOptions().getUserVersion());
+ }
+ catch (NonWritableChannelException e) {
+ // Such exceptions could be thrown when db is opened in "read" mode, but the db file is readonly (for instance, locked
+ // by other process). See links above for some details.
+ // handle this exception type separately - not to break execution flow
+ LOG.info(e);
+ }
+ catch (SqlJetException e) {
+ LOG.info(e);
+ }
+ finally {
+ close(db);
+ }
+ return result;
+ }
+ }
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java
index e5d7dd6c4263..ea623f4d8050 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java
@@ -41,6 +41,12 @@ public class Command {
myParameters.addAll(parameters);
}
+ public void putIfNotPresent(@NotNull String parameter) {
+ if (!myParameters.contains(parameter)) {
+ myParameters.add(parameter);
+ }
+ }
+
@Nullable
public File getConfigDir() {
return myConfigDir;
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java
index c015d0259006..5779ee4a86fb 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.svn.commandLine;
+import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.*;
import com.intellij.openapi.diagnostic.Logger;
@@ -25,6 +26,8 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -40,9 +43,11 @@ public class CommandExecutor {
private boolean myIsDestroyed;
private boolean myNeedsDestroy;
+ private volatile String myDestroyReason;
protected final GeneralCommandLine myCommandLine;
- private Process myProcess;
- private OSProcessHandler myHandler;
+ protected Process myProcess;
+ protected OSProcessHandler myHandler;
+ private OutputStreamWriter myProcessWriter;
// TODO: Try to implement commands in a way that they manually indicate if they need full output - to prevent situations
// TODO: when large amount of data needs to be stored instead of just sequential processing.
private CapturingProcessAdapter outputAdapter;
@@ -86,16 +91,21 @@ public class CommandExecutor {
return myIsDestroyed;
}
+ public String getDestroyReason() {
+ return myDestroyReason;
+ }
+
public void start() {
synchronized (myLock) {
checkNotStarted();
try {
- myProcess = myCommandLine.createProcess();
+ myProcess = createProcess();
if (LOG.isDebugEnabled()) {
LOG.debug(myCommandLine.toString());
}
- myHandler = new OSProcessHandler(myProcess, myCommandLine.getCommandLineString());
+ myHandler = createProcessHandler();
+ myProcessWriter = new OutputStreamWriter(myHandler.getProcessInput());
startHandlingStreams();
} catch (Throwable t) {
listeners().startFailed(t);
@@ -104,7 +114,17 @@ public class CommandExecutor {
}
}
- private void startHandlingStreams() {
+ @NotNull
+ protected OSProcessHandler createProcessHandler() {
+ return new OSProcessHandler(myProcess, myCommandLine.getCommandLineString());
+ }
+
+ @NotNull
+ protected Process createProcess() throws ExecutionException {
+ return myCommandLine.createProcess();
+ }
+
+ protected void startHandlingStreams() {
outputAdapter = new CapturingProcessAdapter();
myHandler.addProcessListener(outputAdapter);
myHandler.addProcessListener(new ProcessTracker());
@@ -121,6 +141,12 @@ public class CommandExecutor {
return outputAdapter.getOutput().getStderr();
}
+ // TODO: Carefully here - do not modify command from threads other than the one started command execution
+ @NotNull
+ public Command getCommand() {
+ return myCommand;
+ }
+
/**
* Wait for process termination
* @param timeout
@@ -183,6 +209,13 @@ public class CommandExecutor {
}
}
+ public void destroyProcess(@Nullable String destroyReason) {
+ synchronized (myLock) {
+ myDestroyReason = destroyReason;
+ myNeedsDestroy = true;
+ }
+ }
+
/**
* ProcessHandler.destroyProcess() implementations could acquire read lock in its implementation - like OSProcessManager.getInstance().
* Some commands are called under write lock - which is generally bad idea, but such logic is not refactored yet.
@@ -265,6 +298,23 @@ public class CommandExecutor {
}
}
+ public void write(String value) throws SvnBindException {
+ try {
+ synchronized (myLock) {
+ myProcessWriter.write(value);
+ myProcessWriter.flush();
+ }
+ }
+ catch (IOException e) {
+ throw new SvnBindException(e);
+ }
+ }
+
+ public void logCommand() {
+ LOG.info("Command text " + getCommandText());
+ LOG.info("Command output " + getOutput());
+ }
+
private class CommandCancelTracker extends LineCommandAdapter {
@Override
public void onLineAvailable(String line, Key outputType) {
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java
index a76f0ecb9c1b..2e9e42097495 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java
@@ -44,7 +44,6 @@ public class CommandParametersResolutionModule extends BaseCommandRuntimeModule
command.setWorkingDirectory(resolveWorkingDirectory(command));
}
command.setConfigDir(myAuthCallback.getSpecialConfigDir());
- command.put("--non-interactive");
command.saveOriginalParameters();
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java
index be097b65948f..67867eab36c0 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java
@@ -17,6 +17,8 @@ package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -85,12 +87,20 @@ public class CommandRuntime {
if (exitCode == null || exitCode != 0) {
logNullExitCode(executor, exitCode);
+ if (executor.isManuallyDestroyed()) {
+ cleanup(executor, command.getWorkingDirectory());
+
+ String destroyReason = executor.getDestroyReason();
+ if (!StringUtil.isEmpty(destroyReason)) {
+ throw new SvnBindException(destroyReason);
+ }
+ }
+
if (executor.getErrorOutput().length() > 0) {
// handle authentication
final String errText = executor.getErrorOutput().trim();
- final AuthCallbackCase callback = createCallback(errText, command.getRepositoryUrl());
+ final AuthCallbackCase callback = executor instanceof TerminalExecutor ? null : createCallback(errText, command.getRepositoryUrl());
if (callback != null) {
- cleanup(executor, command.getWorkingDirectory());
if (callback.getCredentials(errText)) {
if (myAuthCallback.getSpecialConfigDir() != null) {
command.setConfigDir(myAuthCallback.getSpecialConfigDir());
@@ -107,6 +117,9 @@ public class CommandRuntime {
// no errors found in error stream => we treat null exitCode as successful, otherwise exception is thrown
if (exitCode != null) {
// here exitCode != null && exitCode != 0
+ LOG.info("Command - " + executor.getCommandText());
+ LOG.info("Command output - " + executor.getOutput());
+
throw new SvnBindException("Svn process exited with error code: " + exitCode);
}
}
@@ -148,7 +161,7 @@ public class CommandRuntime {
}
private void cleanup(@NotNull CommandExecutor executor, @NotNull File workingDirectory) throws SvnBindException {
- if (executor.isManuallyDestroyed() && executor.getCommandName().isWriteable()) {
+ if (executor.getCommandName().isWriteable()) {
File wcRoot = SvnUtil.getWorkingCopyRootNew(workingDirectory);
// not all commands require cleanup - for instance, some commands operate only with repository - like "svn info <url>"
@@ -167,7 +180,19 @@ public class CommandRuntime {
@NotNull
private CommandExecutor newExecutor(@NotNull Command command) {
- return new CommandExecutor(exePath, command);
+ final CommandExecutor executor;
+
+ if (!Registry.is("svn.use.terminal")) {
+ command.putIfNotPresent("--non-interactive");
+ executor = new CommandExecutor(exePath, command);
+ }
+ else {
+ command.put("--force-interactive");
+ executor = new TerminalExecutor(exePath, command);
+ ((TerminalExecutor)executor).addInteractiveListener(new TerminalSshModule(this, executor));
+ }
+
+ return executor;
}
@NotNull
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/InteractiveCommandListener.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/InteractiveCommandListener.java
new file mode 100644
index 000000000000..a9dc33a7061e
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/InteractiveCommandListener.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2013 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.svn.commandLine;
+
+import com.intellij.openapi.util.Key;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public interface InteractiveCommandListener {
+
+ boolean handlePrompt(String line, Key outputType);
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java
index 48dcfa55abba..860e858c7a8e 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java
@@ -171,6 +171,11 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (SAXException e) {
+ // status parsing errors are logged separately as sometimes there are parsing errors connected to terminal output handling.
+ // these errors primarily occur when status output is rather large.
+ // and status output could be large, for instance, when working copy is locked (seems that each file is listed in status output).
+ command.logCommand();
+
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java
new file mode 100644
index 000000000000..203b25cecf34
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2013 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.svn.commandLine;
+
+import com.intellij.execution.CommandLineUtil;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import com.pty4j.PtyProcess;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class TerminalExecutor extends CommandExecutor {
+
+ // max available value is 480
+ // if greater value is provided than the default value of 80 will be assumed
+ // this could provide unnecessary line breaks and thus could break parsing logic
+ private static final int TERMINAL_WINDOW_MAX_COLUMNS = 480;
+
+ static {
+ if (SystemInfo.isWindows) {
+ System.setProperty("win.pty.cols", String.valueOf(TERMINAL_WINDOW_MAX_COLUMNS));
+ }
+ }
+
+ private final List<InteractiveCommandListener> myInteractiveListeners = ContainerUtil.createLockFreeCopyOnWriteList();
+
+ public TerminalExecutor(@NotNull @NonNls String exePath, @NotNull Command command) {
+ super(exePath, command);
+ }
+
+ public void addInteractiveListener(@NotNull InteractiveCommandListener listener) {
+ myInteractiveListeners.add(listener);
+ }
+
+ @Override
+ protected void startHandlingStreams() {
+ for (InteractiveCommandListener listener : myInteractiveListeners) {
+ ((TerminalProcessHandler)myHandler).addInteractiveListener(listener);
+ }
+
+ super.startHandlingStreams();
+ }
+
+ @NotNull
+ @Override
+ protected OSProcessHandler createProcessHandler() {
+ return new TerminalProcessHandler(myProcess);
+ }
+
+ @NotNull
+ @Override
+ protected Process createProcess() throws ExecutionException {
+ List<String> parameters =
+ escapeArguments(CommandLineUtil.toCommandLine(myCommandLine.getExePath(), myCommandLine.getParametersList().getList()));
+
+ try {
+ return PtyProcess
+ .exec(ArrayUtil.toStringArray(parameters), myCommandLine.getEnvironment(), myCommandLine.getWorkDirectory().getAbsolutePath());
+ }
+ catch (IOException e) {
+ throw new ExecutionException(e);
+ }
+ }
+
+ @Override
+ public void logCommand() {
+ super.logCommand();
+
+ LOG.info("Terminal output " + ((TerminalProcessHandler) myHandler).getTerminalOutput());
+ }
+
+ private static List<String> escapeArguments(List<String> collection) {
+ // TODO: Add additional checks like in java.lang.ProcessImpl constructor
+ return ContainerUtil.map(collection, new Function<String, String>() {
+ @Override
+ public String fun(String s) {
+ return s.contains(" ") ? "\"" + s + "\"" : s;
+ }
+ });
+ }
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java
new file mode 100644
index 000000000000..86fd039ea43c
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2013 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.svn.commandLine;
+
+import com.intellij.execution.process.CapturingProcessAdapter;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.svn.SvnUtil;
+
+import java.util.List;
+import java.util.regex.Matcher;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class TerminalProcessHandler extends OSProcessHandler {
+
+ // see http://en.wikipedia.org/wiki/ANSI_escape_code
+ private static final String NON_CSI_ESCAPE_CODE = "\u001B.[@-_]";
+ private static final String CSI_ESCAPE_CODE = "\u001B\\[(.*?)[@-~]";
+
+ private final List<InteractiveCommandListener> myInteractiveListeners = ContainerUtil.createLockFreeCopyOnWriteList();
+ private final CapturingProcessAdapter terminalOutputCapturer = new CapturingProcessAdapter();
+
+ private final StringBuilder outputLine = new StringBuilder();
+ private final StringBuilder errorLine = new StringBuilder();
+
+ public TerminalProcessHandler(@NotNull Process process) {
+ super(process);
+ }
+
+ public void addInteractiveListener(@NotNull InteractiveCommandListener listener) {
+ myInteractiveListeners.add(listener);
+ }
+
+ @Override
+ protected boolean processHasSeparateErrorStream() {
+ return false;
+ }
+
+ @Override
+ protected void destroyProcessImpl() {
+ final Process process = getProcess();
+ process.destroy();
+ }
+
+ @Override
+ public void notifyTextAvailable(String text, Key outputType) {
+ terminalOutputCapturer.onTextAvailable(new ProcessEvent(this, text), outputType);
+
+ // filter terminal escape codes - they are presented in the output for windows platform
+ String filteredText = text.replaceAll(CSI_ESCAPE_CODE, "").replaceAll(NON_CSI_ESCAPE_CODE, "");
+ // trim leading '\r' symbols - as they break xml parsing logic
+ filteredText = StringUtil.trimLeading(filteredText);
+
+ if (!StringUtil.isEmpty(filteredText)) {
+ StringBuilder lastLine = getLastLineFor(outputType);
+ String currentLine = lastLine.append(filteredText).toString();
+ lastLine.setLength(0);
+
+ // check if current line presents some interactive output
+ boolean handled = false;
+ for (InteractiveCommandListener listener : myInteractiveListeners) {
+ handled |= listener.handlePrompt(currentLine, outputType);
+ }
+
+ if (!handled) {
+ notify(currentLine, outputType, lastLine);
+ }
+ }
+ }
+
+ private void notify(@NotNull String text, @NotNull Key outputType, @NotNull StringBuilder lastLine) {
+ // for windows platform output is assumed in format suitable for terminal emulator
+ // for instance, same text could be returned twice with '\r' symbol in between (so in emulator output we'll still see correct
+ // text without duplication)
+ // because of this we manually process '\r' occurrences to get correct output
+ text = removeAllBeforeCaretReturn(text);
+
+ // text is not more than one line - either one line or part of the line
+ if (StringUtil.endsWith(text, "\n")) {
+ // we have full line - notify listeners
+ super.notifyTextAvailable(text, resolveOutputType(text, outputType));
+ }
+ else {
+ // save line part to lastLine
+ lastLine.append(text);
+ }
+ }
+
+ private static String removeAllBeforeCaretReturn(@NotNull String line) {
+ int caretReturn = line.lastIndexOf("\r");
+
+ while (caretReturn >= 0) {
+ if (caretReturn + 1 < line.length() && line.charAt(caretReturn + 1) != '\n') {
+ // next symbol is not '\n' - we should not treat text before found caret return symbol
+ line = line.substring(caretReturn + 1);
+ break;
+ }
+ caretReturn = line.lastIndexOf("\r", caretReturn - 1);
+ }
+
+ return line;
+ }
+
+ private static Key resolveOutputType(@NotNull String line, @NotNull Key outputType) {
+ Key result = outputType;
+
+ if (!ProcessOutputTypes.SYSTEM.equals(outputType)) {
+ Matcher errorMatcher = SvnUtil.ERROR_PATTERN.matcher(line);
+ Matcher warningMatcher = SvnUtil.WARNING_PATTERN.matcher(line);
+
+ result = errorMatcher.find() || warningMatcher.find() ? ProcessOutputTypes.STDERR : ProcessOutputTypes.STDOUT;
+ }
+
+ return result;
+ }
+
+ @NotNull
+ private StringBuilder getLastLineFor(Key outputType) {
+ if (ProcessOutputTypes.STDERR.equals(outputType)) {
+ return errorLine;
+ }
+ else if (ProcessOutputTypes.STDOUT.equals(outputType)) {
+ return outputLine;
+ }
+ else {
+ throw new IllegalArgumentException("Unknown process output type " + outputType);
+ }
+ }
+
+ public String getTerminalOutput() {
+ return terminalOutputCapturer.getOutput().getStdout();
+ }
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java
new file mode 100644
index 000000000000..b957b9ad8004
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2000-2013 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.svn.commandLine;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Ref;
+import com.intellij.util.WaitForProgressToShow;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.svn.SvnBundle;
+import org.jetbrains.idea.svn.dialogs.ServerSSHDialog;
+import org.jetbrains.idea.svn.dialogs.SimpleCredentialsDialog;
+import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class TerminalSshModule extends LineCommandAdapter implements CommandRuntimeModule, InteractiveCommandListener {
+
+ private static final Logger LOG = Logger.getInstance(TerminalSshModule.class);
+
+ private static final Pattern PASSPHRASE_PROMPT = Pattern.compile("Enter passphrase for key \\'(.*)\\':\\s?");
+ private static final Pattern PASSWORD_PROMPT = Pattern.compile("(.*)\\'s password:\\s?");
+
+ private static final Pattern UNKNOWN_HOST_MESSAGE =
+ Pattern.compile("The authenticity of host \\'((.*) \\((.*)\\))\\' can\\'t be established\\.\\s?");
+ private static final Pattern HOST_FINGERPRINT_MESSAGE = Pattern.compile("(\\w+) key fingerprint is (.*)\\.\\s?");
+ private static final Pattern ACCEPT_HOST_PROMPT = Pattern.compile("Are you sure you want to continue connecting \\(yes/no\\)\\?\\s?");
+
+ @NotNull private final CommandRuntime myRuntime;
+ @NotNull private final CommandExecutor myExecutor;
+
+ private String unknownHost;
+ private String fingerprintAlgorithm;
+ private String hostFingerprint;
+
+ // TODO: Do not accept executor here and make it as command runtime module
+ public TerminalSshModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) {
+ myExecutor = executor;
+ myRuntime = runtime;
+ }
+
+ @Override
+ public void onStart(@NotNull Command command) throws SvnBindException {
+ }
+
+ @Override
+ public boolean handlePrompt(String line, Key outputType) {
+ return checkPassphrase(line) || checkPassword(line) || checkUnknownHost(line);
+ }
+
+ private boolean checkPassphrase(@NotNull String line) {
+ Matcher matcher = PASSPHRASE_PROMPT.matcher(line);
+
+ return matcher.matches() && handleAuthPrompt(SimpleCredentialsDialog.Mode.SSH_PASSPHRASE, matcher.group(1));
+ }
+
+ private boolean checkPassword(@NotNull String line) {
+ Matcher matcher = PASSWORD_PROMPT.matcher(line);
+
+ return matcher.matches() && handleAuthPrompt(SimpleCredentialsDialog.Mode.SSH_PASSWORD, matcher.group(1));
+ }
+
+ private boolean checkUnknownHost(@NotNull String line) {
+ Matcher unknownHostMatcher = UNKNOWN_HOST_MESSAGE.matcher(line);
+ Matcher hostFingerPrintMatcher = HOST_FINGERPRINT_MESSAGE.matcher(line);
+ Matcher acceptHostMatcher = ACCEPT_HOST_PROMPT.matcher(line);
+
+ if (unknownHostMatcher.matches()) {
+ unknownHost = unknownHostMatcher.group(1);
+ }
+ else if (hostFingerPrintMatcher.matches()) {
+ fingerprintAlgorithm = hostFingerPrintMatcher.group(1);
+ hostFingerprint = hostFingerPrintMatcher.group(2);
+ }
+ else if (acceptHostMatcher.matches()) {
+ handleUnknownHost();
+ }
+
+ return unknownHostMatcher.matches() || hostFingerPrintMatcher.matches() || acceptHostMatcher.matches();
+ }
+
+ private void handleUnknownHost() {
+ final Project project = myRuntime.getVcs().getProject();
+ final Ref<Integer> answer = new Ref<Integer>();
+
+ Runnable command = new Runnable() {
+ @Override
+ public void run() {
+ final ServerSSHDialog dialog = new ServerSSHDialog(project, true, unknownHost, fingerprintAlgorithm, hostFingerprint);
+ dialog.show();
+ answer.set(dialog.getResult());
+ }
+ };
+
+ WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command);
+
+ unknownHost = null;
+ fingerprintAlgorithm = null;
+ hostFingerprint = null;
+
+ sendAnswer(answer.get() == ISVNAuthenticationProvider.REJECTED ? "no" : "yes");
+ }
+
+ private boolean handleAuthPrompt(@NotNull final SimpleCredentialsDialog.Mode mode, @NotNull final String key) {
+ @NotNull final SVNURL repositoryUrl = myExecutor.getCommand().getRepositoryUrl();
+ final Project project = myRuntime.getVcs().getProject();
+ final Ref<String> answer = new Ref<String>();
+
+ Runnable command = new Runnable() {
+ public void run() {
+ SimpleCredentialsDialog dialog = new SimpleCredentialsDialog(project);
+ dialog.setup(mode, repositoryUrl.toDecodedString(), key, true);
+ dialog.setTitle(SvnBundle.message("dialog.title.authentication.required"));
+ dialog.show();
+ if (dialog.isOK()) {
+ answer.set(dialog.getPassword());
+ }
+ // TODO: Correctly handle "cancel" - kill the process
+ // TODO: and perform "cleanup" on working copy
+ }
+ };
+
+ WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command);
+
+ if (!answer.isNull()) {
+ sendAnswer(answer.get());
+ } else {
+ myExecutor.destroyProcess("Authentication canceled for repository: " + repositoryUrl);
+ }
+
+ return !answer.isNull();
+ }
+
+ private boolean sendAnswer(@NotNull String answer) {
+ try {
+ myExecutor.write(answer + "\n");
+ return true;
+ }
+ catch (SvnBindException e) {
+ // TODO: handle this more carefully
+ LOG.info(e);
+ }
+ return false;
+ }
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSHDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSHDialog.java
index 30ef5216614c..54e02658b03c 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSHDialog.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSHDialog.java
@@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.dialogs;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnBundle;
@@ -41,12 +42,20 @@ public class ServerSSHDialog extends DialogWrapper {
public ServerSSHDialog(Project project, boolean store, @NotNull final String host, @Nullable final String algorithm,
@NotNull final byte[] fingerprints) {
+ this(project, store, host, algorithm, SVNSSLUtil.getFingerprint(fingerprints, "SHA1"));
+ }
+
+ public ServerSSHDialog(Project project,
+ boolean store,
+ @NotNull final String host,
+ @Nullable final String algorithm,
+ @NotNull String fingerprints) {
super(project, true);
myStore = store;
myHost = host;
- myAlgorithm = algorithm == null ? "" : algorithm;
+ myAlgorithm = StringUtil.notNullize(algorithm);
// todo ?
- myFingerprints = SVNSSLUtil.getFingerprint(fingerprints, "SHA1");
+ myFingerprints = fingerprints;
myResult = ISVNAuthenticationProvider.REJECTED;
setOKButtonText(SvnBundle.message("button.text.ssh.accept"));
setCancelButtonText(SvnBundle.message("button.text.ssh.reject"));
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleCredentialsDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleCredentialsDialog.java
index 3c11acb0e14b..f779c0c359d5 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleCredentialsDialog.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleCredentialsDialog.java
@@ -34,6 +34,7 @@ import java.awt.*;
public class SimpleCredentialsDialog extends DialogWrapper implements DocumentListener {
private boolean myAllowSave;
private String myUserName;
+ private Mode myMode;
private String myRealm;
private JTextField myUserNameText;
@@ -42,18 +43,24 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
@NonNls private static final String HELP_ID = "vcs.subversion.authentication";
- protected SimpleCredentialsDialog(Project project) {
+ public SimpleCredentialsDialog(Project project) {
super(project, true);
setResizable(false);
}
public void setup(String realm, String userName, boolean allowSave) {
+ setup(Mode.DEFAULT, realm, userName, allowSave);
+ }
+
+ public void setup(Mode mode, String realm, String userName, boolean allowSave) {
+ myMode = mode;
myRealm = realm;
myUserName = userName;
myAllowSave = allowSave;
getHelpAction().setEnabled(true);
init();
}
+
protected void doHelpAction() {
HelpManager.getInstance().invokeHelp(HELP_ID);
}
@@ -89,7 +96,7 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
gb.weightx = 0;
gb.fill = GridBagConstraints.NONE;
- label = new JLabel(SvnBundle.message("label.auth.user.name"));
+ label = new JLabel(SvnBundle.message(myMode.equals(Mode.SSH_PASSPHRASE) ? "label.ssh.key.file" : "label.auth.user.name"));
panel.add(label, gb);
// user name field
@@ -106,6 +113,7 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
}
myUserNameText.selectAll();
myUserNameText.getDocument().addDocumentListener(this);
+ myUserNameText.setEnabled(myMode.equals(Mode.DEFAULT));
gb.gridy += 1;
gb.weightx = 0;
@@ -113,7 +121,7 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
gb.fill = GridBagConstraints.NONE;
gb.gridwidth = 1;
- label = new JLabel(SvnBundle.message("label.auth.password"));
+ label = new JLabel(SvnBundle.message(myMode.equals(Mode.SSH_PASSPHRASE) ? "label.ssh.passphrase" : "label.auth.password"));
panel.add(label, gb);
// passworde field
@@ -152,7 +160,7 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
}
public JComponent getPreferredFocusedComponent() {
- return myUserNameText;
+ return myUserNameText.isEnabled() ? myUserNameText : myPasswordText;
}
public boolean shouldCloseOnCross() {
@@ -197,4 +205,10 @@ public class SimpleCredentialsDialog extends DialogWrapper implements DocumentLi
private void updateOKButton() {
getOKAction().setEnabled(isOKActionEnabled());
}
+
+ public enum Mode {
+ SSH_PASSPHRASE,
+ SSH_PASSWORD,
+ DEFAULT
+ }
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ToBeMergedDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ToBeMergedDialog.java
index 620bc38f6ece..19a8832b0b45 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ToBeMergedDialog.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ToBeMergedDialog.java
@@ -296,7 +296,7 @@ public class ToBeMergedDialog extends DialogWrapper implements MergeDialogI {
myRevisionsList.setShowGrid(false);
final AbstractBaseTagMouseListener mouseListener = new AbstractBaseTagMouseListener() {
@Override
- protected Object getTagAt(MouseEvent e) {
+ public Object getTagAt(MouseEvent e) {
Object tag = null;
JTable table = (JTable)e.getSource();
int row = table.rowAtPoint(e.getPoint());
diff --git a/plugins/svn4idea/svn4idea.iml b/plugins/svn4idea/svn4idea.iml
index 53dd66166d64..1765d1aede98 100644
--- a/plugins/svn4idea/svn4idea.iml
+++ b/plugins/svn4idea/svn4idea.iml
@@ -76,6 +76,9 @@
</SOURCES>
</library>
</orderEntry>
+ <orderEntry type="library" name="jna" level="project" />
+ <orderEntry type="library" name="pty4j" level="project" />
+ <orderEntry type="library" name="purejavacomm" level="project" />
</component>
</module>