Mercurial > hg > mercurial
changeset 1029:9123ad25b082
Trying to solve HG problem with multiple heads
author | nikolai.kulakov@DESKTOP-Q4QCGIH |
---|---|
date | Thu, 06 Aug 2020 12:15:36 +0300 |
parents | 0699b46a3d2a (diff) 62fe3e69cee6 (current diff) |
children | 1c65ee703a92 |
files | mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java |
diffstat | 999 files changed, 143422 insertions(+), 8468 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Fri Sep 24 19:45:30 2010 +0400 +++ b/.hgignore Thu Aug 06 12:15:36 2020 +0300 @@ -2,3 +2,8 @@ test-output .iws dist +mercurial.properties +syntax: glob +.idea/workspace.xml +out +.DS_Store \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgtags Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,10 @@ +9e60b6d1e5fd8ed9a0c4b9582facc727a16bdcdb build-snapshot-124 +b454327bcb66c35f17ae171a794d540768fc32b4 build-snapshot-125 +0b54319af42cd1e74c1a658d61ecf1c3e6fc91a1 build-snapshot-126 +3a41cf31c90e299237fb1258f9ab363e7e0f9454 build-snapshot-127 +9c29eab7a27c80045948efb1cc094b96b4d82ea5 build-snapshot-128 +45a4b3169272f8d21ff802b25a28e16b46177d26 build-snapshot-129 +ff587c27a2d07607242cc02919c3db8cd4808ca2 build-snapshot-130 +9a52e7a891ce7bbb0f5df0f94483f1636359e73d build-snapshot-131 +df6ed5ed6c105ba2c65a3df1e3dc556f7882681b build-snapshot-133 +9998e944a4f2b19d10621d06c230144c5a68204b build-snapshot-134
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/ant.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="AntConfiguration"> + <buildFile url="file://$PROJECT_DIR$/build/ant.build.xml" /> + </component> +</project> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/mercurial_agent_jar.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,14 @@ +<component name="ArtifactManager"> + <artifact type="jar" name="mercurial-agent.jar"> + <output-path>$PROJECT_DIR$/out/artifacts/mercurial_agent_jar</output-path> + <properties id="ant-postprocessing"> + <options enabled="true"> + <file>file://$PROJECT_DIR$/build/ant.build.xml</file> + <target>replace-tokens-in-teamcity-plugin-xml</target> + </options> + </properties> + <root id="archive" name="mercurial-agent.jar"> + <element id="module-output" name="mercurial-agent" /> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/mercurial_common_jar.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,11 @@ +<component name="ArtifactManager"> + <artifact type="jar" name="mercurial-common.jar"> + <output-path>$PROJECT_DIR$/out/artifacts/mercurial_common_jar</output-path> + <root id="archive" name="mercurial-common.jar"> + <element id="module-output" name="mercurial-common" /> + <element id="directory" name="python"> + <element id="dir-copy" path="$PROJECT_DIR$/mercurial-common/src/python" /> + </element> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/mercurial_server_jar.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,8 @@ +<component name="ArtifactManager"> + <artifact type="jar" name="mercurial-server.jar"> + <output-path>$PROJECT_DIR$/out/artifacts/mercurial_server_jar</output-path> + <root id="archive" name="mercurial-server.jar"> + <element id="module-output" name="mercurial-server" /> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/mercurial_server_tc_jar.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,8 @@ +<component name="ArtifactManager"> + <artifact type="jar" name="mercurial-server-tc.jar"> + <output-path>$PROJECT_DIR$/out/artifacts/mercurial_server_tc_jar</output-path> + <root id="archive" name="mercurial-server-tc.jar"> + <element id="module-output" name="mercurial-server-tc" /> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/mercurial_vcs_worker.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,21 @@ +<component name="ArtifactManager"> + <artifact name="mercurial-vcs-worker"> + <output-path>$PROJECT_DIR$/out/artifacts/mercurial_vcs_worker</output-path> + <properties id="ant-postprocessing"> + <options enabled="true"> + <file>file://$PROJECT_DIR$/build/ant.build.xml</file> + <target>replace-tokens-in-teamcity-plugin-xml</target> + </options> + </properties> + <root id="root"> + <element id="directory" name="lib"> + <element id="artifact" artifact-name="mercurial-common.jar" /> + <element id="artifact" artifact-name="mercurial-server.jar" /> + <element id="library" level="project" name="quartz-1.6.0" /> + <element id="library" level="project" name="commons-compress-1.5" /> + <element id="library" level="project" name="commons-codec-1.4" /> + </element> + <element id="file-copy" path="$PROJECT_DIR$/teamcity-plugin.xml" /> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/plugin.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,42 @@ +<component name="ArtifactManager"> + <artifact name="plugin"> + <output-path>$PROJECT_DIR$/out/artifacts/plugin</output-path> + <properties id="ant-postprocessing"> + <options enabled="true"> + <file>file://$PROJECT_DIR$/build/ant.build.xml</file> + <target>replace-tokens-in-teamcity-plugin-xml</target> + </options> + </properties> + <root id="root"> + <element id="directory" name="server"> + <element id="artifact" artifact-name="mercurial-server.jar" /> + <element id="artifact" artifact-name="mercurial-common.jar" /> + <element id="artifact" artifact-name="mercurial-server-tc.jar" /> + <element id="library" level="project" name="quartz-1.6.0" /> + <element id="library" level="project" name="commons-compress-1.5" /> + <element id="library" level="project" name="commons-codec-1.4" /> + </element> + <element id="directory" name="agent"> + <element id="archive" name="mercurial.zip"> + <element id="directory" name="mercurial"> + <element id="directory" name="lib"> + <element id="artifact" artifact-name="mercurial-common.jar" /> + <element id="artifact" artifact-name="mercurial-agent.jar" /> + <element id="library" level="project" name="commons-codec-1.4" /> + <element id="library" level="project" name="commons-compress-1.5" /> + </element> + </element> + </element> + </element> + <element id="file-copy" path="$PROJECT_DIR$/teamcity-plugin.xml" /> + <element id="directory" name="vcs-worker"> + <element id="archive" name="mercurial.zip"> + <element id="artifact" artifact-name="mercurial-vcs-worker" /> + </element> + </element> + <element id="directory" name="kotlin-dsl"> + <element id="file-copy" path="$PROJECT_DIR$/mercurial-dsl/HgVcsRoot.xml" /> + </element> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/artifacts/zip.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,10 @@ +<component name="ArtifactManager"> + <artifact name="zip"> + <output-path>$PROJECT_DIR$/dist</output-path> + <root id="root"> + <element id="archive" name="mercurial.zip"> + <element id="artifact" artifact-name="plugin" /> + </element> + </root> + </artifact> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/codeStyleSettings.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectCodeStyleSettingsManager"> + <option name="PER_PROJECT_SETTINGS"> + <value> + <option name="USE_SAME_INDENTS" value="true" /> + <option name="IGNORE_SAME_INDENTS_FOR_LANGUAGES" value="true" /> + <option name="OTHER_INDENT_OPTIONS"> + <value> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="2" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </value> + </option> + <option name="LINE_SEPARATOR" value=" " /> + <option name="FIELD_NAME_PREFIX" value="my" /> + <option name="STATIC_FIELD_NAME_PREFIX" value="our" /> + <option name="RIGHT_MARGIN" value="140" /> + <XML> + <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> + </XML> + <codeStyleSettings language="CSS"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="CoffeeScript"> + <indentOptions> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="Groovy"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="JAVA"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="JSP"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="JavaScript"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="XML"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="jet"> + <indentOptions> + <option name="INDENT_SIZE" value="2" /> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + <codeStyleSettings language="yaml"> + <indentOptions> + <option name="TAB_SIZE" value="2" /> + </indentOptions> + </codeStyleSettings> + </value> + </option> + <option name="USE_PER_PROJECT_SETTINGS" value="true" /> + </component> +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/compiler.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="CompilerConfiguration"> + <option name="DEFAULT_COMPILER" value="Javac" /> + <resourceExtensions> + <entry name=".+\.(properties|xml|html|dtd|tld)" /> + <entry name=".+\.(gif|png|jpeg|jpg)" /> + </resourceExtensions> + <wildcardResourcePatterns> + <entry name="?*.properties" /> + <entry name="?*.xml" /> + <entry name="?*.gif" /> + <entry name="?*.png" /> + <entry name="?*.jpeg" /> + <entry name="?*.jpg" /> + <entry name="?*.html" /> + <entry name="?*.dtd" /> + <entry name="?*.tld" /> + <entry name="?*.jsp" /> + <entry name="?*.tag" /> + <entry name="?*.template" /> + <entry name="do-not-load-in-vcs-mode" /> + <entry name="?*.py" /> + </wildcardResourcePatterns> + <annotationProcessing> + <profile default="true" name="Default" enabled="false"> + <processorPath useClasspath="true" /> + </profile> + </annotationProcessing> + </component> +</project> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/copyright/open_source.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="CopyrightManager"> + <copyright> + <option name="notice" value="Copyright 2000-&#36;today.year 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." /> + <option name="keyword" value="Copyright" /> + <option name="allowReplaceKeyword" value="" /> + <option name="myName" value="open-source" /> + <option name="myLocal" value="true" /> + </copyright> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/copyright/profiles_settings.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,7 @@ +<component name="CopyrightManager"> + <settings default=""> + <module2copyright> + <element module="All" copyright="open-source" /> + </module2copyright> + </settings> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/encodings.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false"> + <file url="PROJECT" charset="UTF-8" /> + </component> +</project> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/inspectionProfiles/Project_Default.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,11 @@ +<component name="InspectionProjectProfileManager"> + <profile version="1.0" is_locked="false"> + <option name="myName" value="Project Default" /> + <option name="myLocal" value="false" /> + <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> + <option name="processCode" value="true" /> + <option name="processLiterals" value="true" /> + <option name="processComments" value="true" /> + </inspection_tool> + </profile> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/inspectionProfiles/profiles_settings.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,15 @@ +<component name="InspectionProjectProfileManager"> + <settings> + <option name="PROJECT_PROFILE" value="Project Default" /> + <option name="USE_PROJECT_PROFILE" value="true" /> + <version value="1.0" /> + <list size="6"> + <item index="0" class="java.lang.String" itemvalue="TYPO" /> + <item index="1" class="java.lang.String" itemvalue="WEAK WARNING" /> + <item index="2" class="java.lang.String" itemvalue="INFO" /> + <item index="3" class="java.lang.String" itemvalue="WARNING" /> + <item index="4" class="java.lang.String" itemvalue="ERROR" /> + <item index="5" class="java.lang.String" itemvalue="SERVER PROBLEM" /> + </list> + </settings> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/IDEA_openapi.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,12 @@ +<component name="libraryTable"> + <library name="IDEA-openapi"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/resources_en.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/util.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/openapi.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/annotations.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/JMock.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,15 @@ +<component name="libraryTable"> + <library name="JMock"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/hamcrest-library-1.1.jar!/" /> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/hamcrest-core-1.1.jar!/" /> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/jmock-2.5.1.jar!/" /> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/jmock-SNAPSHOT.jar!/" /> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/hamcrest-integration-1.1.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/hamcrest-integration-1.1.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/JUnit.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="JUnit"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/junit-3.8.1.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/Log4j.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="Log4j"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/log4j-1.2.12.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCityAPI_agent.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,12 @@ +<component name="libraryTable"> + <library name="TeamCityAPI-agent"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/devPackage/agent-api.jar!/" /> + <root url="jar://$TeamCityDistribution$/buildAgent/lib/agent.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$TeamCityDistribution$/devPackage/src/openApi-source.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCityAPI_common.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,14 @@ +<component name="libraryTable"> + <library name="TeamCityAPI-common"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/devPackage/common-api.jar!/" /> + <root url="jar://$TeamCityDistribution$/devPackage/serviceMessages.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/commons-httpclient-3.1.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/commons-logging.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$TeamCityDistribution$/devPackage/src/openApi-source.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCityAPI_server.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,12 @@ +<component name="libraryTable"> + <library name="TeamCityAPI-server"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/devPackage/server-api.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/server.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$TeamCityDistribution$/devPackage/src/openApi-source.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCity_TestsAPI.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,10 @@ +<component name="libraryTable"> + <library name="TeamCity-TestsAPI"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/devPackage/tests/patches-test.jar!/" /> + <root url="jar://$TeamCityDistribution$/devPackage/tests/tests-support.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCity_Vcs_Api.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,12 @@ +<component name="libraryTable"> + <library name="TeamCity Vcs Api"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/devPackage/server-common-api.jar!/" /> + <root url="jar://$TeamCityDistribution$/devPackage/server-vcs-api.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$TeamCityDistribution$/devPackage/src/openApi-source.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TeamCity_impl.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,11 @@ +<component name="libraryTable"> + <library name="TeamCity-impl"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/patches-impl.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove4j.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove-3.0.3.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/TestNG.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="TestNG"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/mercurial-tests/lib/testng-6.8.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/commons_codec_1_4.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="commons-codec-1.4"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/commons-codec-1.4.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/commons_compress_1_5.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="commons-compress-1.5"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/commons-compress-1.5.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/jdom.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="jdom"> + <CLASSES> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/jdom.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/quartz_1_6_0.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="quartz-1.6.0"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/quartz-1.6.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/libraries/trove4j.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,9 @@ +<component name="libraryTable"> + <library name="trove4j"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/trove4j.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/misc.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="EntryPointsManager"> + <entry_points version="2.0" /> + </component> + <component name="IdProvider" IDEtalkID="C52C76224CD45BEC1DC62428B699D800" /> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" /> +</project> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/modules.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" /> + <module fileurl="file://$PROJECT_DIR$/mercurial-agent/mercurial-agent.iml" filepath="$PROJECT_DIR$/mercurial-agent/mercurial-agent.iml" /> + <module fileurl="file://$PROJECT_DIR$/mercurial-common/mercurial-common.iml" filepath="$PROJECT_DIR$/mercurial-common/mercurial-common.iml" /> + <module fileurl="file://$PROJECT_DIR$/mercurial-server/mercurial-server.iml" filepath="$PROJECT_DIR$/mercurial-server/mercurial-server.iml" /> + <module fileurl="file://$PROJECT_DIR$/mercurial-server-tc/mercurial-server-tc.iml" filepath="$PROJECT_DIR$/mercurial-server-tc/mercurial-server-tc.iml" /> + <module fileurl="file://$PROJECT_DIR$/mercurial-tests/mercurial-tests.iml" filepath="$PROJECT_DIR$/mercurial-tests/mercurial-tests.iml" /> + </modules> + </component> +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/runConfigurations/tests.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,38 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="tests" type="TestNG" factoryName="TestNG"> + <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" /> + <module name="mercurial-tests" /> + <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> + <option name="ALTERNATIVE_JRE_PATH" value="" /> + <option name="SUITE_NAME" value="$PROJECT_DIR$/mercurial-tests/src/testng.xml" /> + <option name="PACKAGE_NAME" value="" /> + <option name="MAIN_CLASS_NAME" value="" /> + <option name="METHOD_NAME" value="" /> + <option name="GROUP_NAME" value="" /> + <option name="TEST_OBJECT" value="SUITE" /> + <option name="VM_PARAMETERS" value="-ea" /> + <option name="PARAMETERS" value="" /> + <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" /> + <option name="OUTPUT_DIRECTORY" value="" /> + <option name="ANNOTATION_TYPE" /> + <option name="ENV_VARIABLES" /> + <option name="PASS_PARENT_ENVS" value="true" /> + <option name="TEST_SEARCH_SCOPE"> + <value defaultName="moduleWithDependencies" /> + </option> + <option name="USE_DEFAULT_REPORTERS" value="false" /> + <option name="PROPERTIES_FILE" value="" /> + <envs /> + <properties /> + <listeners /> + <RunnerSettings RunnerId="Debug"> + <option name="DEBUG_PORT" value="51735" /> + <option name="TRANSPORT" value="0" /> + <option name="LOCAL" value="true" /> + </RunnerSettings> + <RunnerSettings RunnerId="Run" /> + <ConfigurationWrapper RunnerId="Debug" /> + <ConfigurationWrapper RunnerId="Run" /> + <method /> + </configuration> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/runConfigurations/tests_via_file.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,32 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="tests via file" type="TestNG" factoryName="TestNG"> + <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" /> + <module name="mercurial-tests" /> + <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> + <option name="ALTERNATIVE_JRE_PATH" value="" /> + <option name="SUITE_NAME" value="$PROJECT_DIR$/mercurial-tests/src/testng-via-cmd.xml" /> + <option name="PACKAGE_NAME" value="" /> + <option name="MAIN_CLASS_NAME" value="" /> + <option name="METHOD_NAME" value="" /> + <option name="GROUP_NAME" value="" /> + <option name="TEST_OBJECT" value="SUITE" /> + <option name="VM_PARAMETERS" value="-ea -Dteamcity.mercurial.use.commandline.via.file.wrapper=true" /> + <option name="PARAMETERS" value="" /> + <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" /> + <option name="OUTPUT_DIRECTORY" value="" /> + <option name="ANNOTATION_TYPE" /> + <option name="ENV_VARIABLES" /> + <option name="PASS_PARENT_ENVS" value="true" /> + <option name="TEST_SEARCH_SCOPE"> + <value defaultName="moduleWithDependencies" /> + </option> + <option name="USE_DEFAULT_REPORTERS" value="false" /> + <option name="PROPERTIES_FILE" value="" /> + <envs /> + <properties /> + <listeners /> + <RunnerSettings RunnerId="Run" /> + <ConfigurationWrapper RunnerId="Run" /> + <method /> + </configuration> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/scopes/scope_settings.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,5 @@ +<component name="DependencyValidationManager"> + <state> + <option name="SKIP_IMPORT_STATEMENTS" value="false" /> + </state> +</component> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/uiDesigner.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="Palette2"> + <group name="Swing"> + <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" /> + </item> + <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true"> + <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" /> + <initial-values> + <property name="text" value="Button" /> + </initial-values> + </item> + <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="RadioButton" /> + </initial-values> + </item> + <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="CheckBox" /> + </initial-values> + </item> + <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="Label" /> + </initial-values> + </item> + <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1"> + <preferred-size width="-1" height="20" /> + </default-constraints> + </item> + <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" /> + </item> + </group> + </component> +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/vcs.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="hg4idea" /> + </component> +</project> +
--- a/README.txt Fri Sep 24 19:45:30 2010 +0400 +++ b/README.txt Thu Aug 06 12:15:36 2020 +0300 @@ -3,6 +3,8 @@ Installation ================================= -TeamCity 4.x/5.x +TeamCity 4.x and later Download mercurial-server.zip and put it into the .BuildServer/plugins folder. Restart server. + +
--- a/build.xml Fri Sep 24 19:45:30 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -<project name="Mercurial VCS Support" default="dist" basedir="."> - <property file="mercurial.properties"/> - <import file="mercurial.xml"/> - - <property name="distPath" value="${basedir}/dist"/> - - <property name="plugin.name" value="mercurial"/> - - <import file="teamcity-common.xml"/> - - <target name="package" depends="define.version"> - <package.teamcity.plugin name="${plugin.name}" - server.output="${mercurial-server.output.dir}" - agent.output="${mercurial-agent.output.dir}" - common.output="${mercurial-common.output.dir}" - plugin.descriptor.file="${basedir}/teamcity-plugin.xml" - plugin.version="${plugin.version}"/> - </target> - - <target name="define.version" depends="define.version.if.under.teamcity"> - <tstamp> - <format property="current.time" pattern="yyyyMMddHHmm"/> - </tstamp> - <property name="plugin.version" value="SNAPSHOT-${current.time}"/> - </target> - - <target name="define.version.if.under.teamcity" if="build.number"> - <property name="plugin.version" value="${build.number}"/> - </target> - - <target name="dist" depends="check.teamcitydistribution,all,package"/> - - <taskdef name="testng" classname="org.testng.TestNGAntTask" classpath="${basedir}/mercurial-tests/lib/testng-5.7-jdk15.jar"/> - - <path id="tests_classpath"> - <pathelement location="${agent.home.dir}/lib/runtime-util.jar"/> - <pathelement location="${agent.home.dir}/lib/buildServerRuntimeUtil.jar"/> - <path refid="mercurial-tests.runtime.module.classpath"/> - </path> - - <target name="run-tests" depends="clean, init, compile.module.mercurial-tests"> - <property name="suspend" value="n"/> - - <testng haltonfailure="no" failureProperty="failure_found" listener="org.testng.reporters.TestHTMLReporter" - outputdir="${basedir}/test-output" classpathref="tests_classpath" dumpcommand="true" workingDir="${basedir}"> - - <jvmarg value="-ea"/> - <!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=${suspend},address=5555"/>--> - - <sysproperty key="java.awt.headless" value="true"/> - - <xmlfileset dir="${basedir}/mercurial-tests/src"> - <include name="testng.xml"/> - </xmlfileset> - </testng> - </target> -</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build/ant.build.xml Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,47 @@ +<!-- + ~ Copyright 2000-2018 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. + --> + +<project name="build hooks" default="replace-tokens-in-teamcity-plugin-xml" basedir="."> + + <target name="replace-tokens-in-teamcity-plugin-xml"> + <property name="home" value="${artifact.output.path}"/> + + <tstamp> + <format property="timestamp" pattern="yyyyMMddhhmmss"/> + </tstamp> + + <property name="snapshot.build.number" value="SNAPSHOT-${timestamp}"/> + + <condition property="plugin.version" value="${snapshot.build.number}" else="${build.number}"> + <or> + <not> + <isset property="build.number"/> + </not> + <matches pattern="snapshot-.*" string="${build.number}" casesensitive="false"/> + </or> + </condition> + + <echo message="replacing tokens in teamcity-plugin.xml file under ${home}"/> + <echo message="Setting version to: ${plugin.version}"/> + + <!-- update all references in teamcity-plugin.xml files --> + <replace dir="${home}" summary="true"> + <include name="**/teamcity-plugin.xml"/> + <replacefilter token="@version@" value="${plugin.version}"/> + </replace> + </target> + +</project>
--- a/mercurial-agent/mercurial-agent.iml Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-agent/mercurial-agent.iml Thu Aug 06 12:15:36 2020 +0300 @@ -5,16 +5,15 @@ <configuration /> </facet> </component> - <component name="NewModuleRootManager" inherit-compiler-output="false"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false"> <output url="file://$MODULE_DIR$/classes" /> <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> </content> - <orderEntry type="inheritedJdk" /> + <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="library" name="TeamCityAPI-agent" level="project" /> <orderEntry type="module" module-name="mercurial-common" /> </component> -</module> - +</module> \ No newline at end of file
--- a/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Thu Aug 06 12:15:36 2020 +0300 @@ -1,6 +1,36 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> - -<beans default-autowire="constructor"> - <bean id="mercurialAgent" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> -</beans> +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2000-2018 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. + --> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" + default-autowire="constructor"> + <bean id="mercurialAgent" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> + <bean id="hgPathProvider" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentHgPathProvider" /> + <bean id="hgDetector" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgDetector" /> + <bean id="pluginConfig" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentPluginConfigImpl"/> + <bean id="mirrorManager" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerImpl" /> + <bean id="mirrorCleaner" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentMirrorCleaner" /> + <bean id="commandSettingsFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentCommandSettingsFactory" /> + <bean id="agentRepoFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentRepoFactory"/> + + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver"/> + + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.MercurialExtensionManager"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.impl.SparseCheckoutProvider"/> +</beans>
--- a/mercurial-agent/src/build-agent-plugin.xml Fri Sep 24 19:45:30 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -<!-- -PicoContainer configuration for old fashioned TeamCity agent plugins. -In TeamCity 4.0 Spring configuration must be created instead. ---> -<container> - <component class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> -</container> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentCommandSettingsFactory.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import org.jetbrains.annotations.NotNull; + +public class AgentCommandSettingsFactory implements CommandSettingsFactory { + + @NotNull + public CommandSettings create() { + return new CommandSettings().setLogLevel("info"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentHgPathProvider.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.parameters.ProcessingResult; +import jetbrains.buildServer.parameters.ValueResolver; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class AgentHgPathProvider implements HgPathProvider { + + private final ValueResolver myResolver; + + + public AgentHgPathProvider(@NotNull final BuildAgentConfiguration agentConfig) { + myResolver = agentConfig.getParametersResolver(); + } + + + public String getHgPath(@NotNull final HgVcsRoot root) { + String pathFromRoot = root.getHgPath(); + return resolve(pathFromRoot); + } + + + private String resolve(@NotNull final String value) { + ProcessingResult result = myResolver.resolve(value); + return result.getResult(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleaner.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.agent.DirectoryCleanersProvider; +import jetbrains.buildServer.agent.DirectoryCleanersProviderContext; +import jetbrains.buildServer.agent.DirectoryCleanersRegistry; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.VcsRootEntry; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author dmitry.neverov + */ +public class AgentMirrorCleaner implements DirectoryCleanersProvider { + + private final static Logger ourLog = Logger.getInstance(AgentMirrorCleaner.class.getName()); + private final MirrorManager myMirrorManager; + + public AgentMirrorCleaner(@NotNull final MirrorManager mirrorManager) { + myMirrorManager = mirrorManager; + } + + @NotNull + public String getCleanerName() { + return "Mercurial mirrors cleaner"; + } + + public void registerDirectoryCleaners(@NotNull DirectoryCleanersProviderContext context, + @NotNull DirectoryCleanersRegistry registry) { + Set<String> repositoriesUsedInBuild = getRunningBuildRepositories(context); + for (Map.Entry<String, File> entry : myMirrorManager.getMappings().entrySet()) { + String repository = entry.getKey(); + File mirror = entry.getValue(); + if (!repositoriesUsedInBuild.contains(repository)) { + ourLog.debug("Register cleaner for mirror " + mirror.getAbsolutePath()); + registry.addCleaner(mirror, new Date(myMirrorManager.getLastUsedTime(mirror))); + } + } + } + + private Set<String> getRunningBuildRepositories(@NotNull DirectoryCleanersProviderContext context) { + Set<String> repositories = new HashSet<>(); + for (VcsRootEntry entry : context.getRunningBuild().getVcsRootEntries()) { + VcsRoot root = entry.getVcsRoot(); + if (!isHgRoot(root)) + continue; + HgVcsRoot hgRoot = new HgVcsRoot(root); + AuthSettings auth = hgRoot.getAuthSettings(); + ourLog.debug("Repository " + auth.getRepositoryUrlWithHiddenPassword(hgRoot.getRepository()) + + " is used in the build, its mirror won't be cleaned"); + repositories.add(hgRoot.getRepository()); + } + return repositories; + } + + private boolean isHgRoot(@NotNull VcsRoot root) { + return Constants.VCS_NAME.equals(root.getVcsName()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public interface AgentPluginConfig extends PluginConfig { + + boolean isUseLocalMirrors(@NotNull AgentRunningBuild build, @NotNull VcsRoot root); + + boolean shareLocalMirrors(@NotNull AgentRunningBuild build, @NotNull VcsRoot root); + + int getPullTimeout(@NotNull AgentRunningBuild build); + + boolean runWithTraceback(@NotNull AgentRunningBuild build); + + boolean runWithProfile(@NotNull AgentRunningBuild build); + + @NotNull + File getTempDir(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.util.StringUtil; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class AgentPluginConfigImpl implements AgentPluginConfig { + + private static final String PULL_TIMEOUT_SECONDS = "teamcity.hg.pull.timeout.seconds"; + private static final int DEFAULT_PULL_TIMEOUT_SECONDS = 3600; + public static final String VCS_ROOT_MIRRORS_STRATEGY = "teamcity.hg.mirrorStrategy"; + public static final String VCS_ROOT_MIRRORS_STRATEGY_SHARED_MIRRORS = "sharedMirrors"; + public static final String VCS_ROOT_MIRRORS_STRATEGY_MIRRORS_ONLY = "mirrors"; + + private final BuildAgentConfiguration myAgentConfig; + + public AgentPluginConfigImpl(@NotNull BuildAgentConfiguration agentConfig) { + myAgentConfig = agentConfig; + } + + public boolean isUseLocalMirrors(@NotNull AgentRunningBuild build, @NotNull VcsRoot root) { + String buildValue = build.getSharedConfigParameters().get("teamcity.hg.use.local.mirrors"); + if (!StringUtil.isEmpty(buildValue)) + return Boolean.parseBoolean(buildValue); + HgVcsRoot hgRoot = new HgVcsRoot(root); + Boolean rootValue = hgRoot.getUseAgentMirrors(); + String mirrorStrategy = getMirrorStrategy(build); + if (rootValue != null && rootValue && (VCS_ROOT_MIRRORS_STRATEGY_SHARED_MIRRORS.equals(mirrorStrategy) || VCS_ROOT_MIRRORS_STRATEGY_MIRRORS_ONLY.equals(mirrorStrategy))) + return true; + return false; + } + + @SuppressWarnings("ConstantConditions") + public boolean shareLocalMirrors(@NotNull AgentRunningBuild build, @NotNull VcsRoot root) { + String buildValue = build.getSharedConfigParameters().get("teamcity.hg.shareLocalMirrors"); + if (!StringUtil.isEmpty(buildValue)) + return Boolean.parseBoolean(buildValue); + HgVcsRoot hgRoot = new HgVcsRoot(root); + Boolean rootValue = hgRoot.getUseAgentMirrors(); + String mirrorStrategy = getMirrorStrategy(build); + if (rootValue != null && rootValue && VCS_ROOT_MIRRORS_STRATEGY_SHARED_MIRRORS.equals(mirrorStrategy)) + return true; + return false; + } + + @NotNull + private String getMirrorStrategy(@NotNull AgentRunningBuild build) { + String strategy = build.getSharedConfigParameters().get(VCS_ROOT_MIRRORS_STRATEGY); + if (!StringUtil.isEmpty(strategy)) + return strategy; + return VCS_ROOT_MIRRORS_STRATEGY_SHARED_MIRRORS; + } + + @NotNull + public File getCachesDir() { + return myAgentConfig.getCacheDirectory("mercurial"); + } + + public int getPullTimeout(@NotNull AgentRunningBuild build) { + Integer timeout = parseTimeout(build.getSharedConfigParameters().get(PULL_TIMEOUT_SECONDS)); + if (timeout != null) + return timeout; + return DEFAULT_PULL_TIMEOUT_SECONDS; + } + + public boolean runWithTraceback(@NotNull AgentRunningBuild build) { + return Boolean.parseBoolean(build.getSharedConfigParameters().get("teamcity.hg.run.commands.with.traceback")); + } + + public boolean runWithProfile(@NotNull AgentRunningBuild build) { + return Boolean.parseBoolean(build.getSharedConfigParameters().get("teamcity.hg.runCommandsWithProfile")); + } + + @Nullable + public Integer parseTimeout(@Nullable String timeoutStr) { + if (timeoutStr == null) + return null; + try { + int timeout = Integer.parseInt(timeoutStr); + if (timeout > 0) + return timeout; + else + return null; + } catch (NumberFormatException e) { + return null; + } + } + + @NotNull + public File getTempDir() { + return myAgentConfig.getTempDirectory(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentRepoFactory.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRoot; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class AgentRepoFactory implements HgRepoFactory { + + private final AgentPluginConfig myPluginConfig; + private final CommandSettingsForRoot myCommandSettingsFactory; + private final HgPathProvider myHgPathProvider; + + public AgentRepoFactory(@NotNull AgentPluginConfig pluginConfig, + @NotNull CommandSettingsForRoot commandSettingsFactory, + @NotNull HgPathProvider hgPathProvider) { + myPluginConfig = pluginConfig; + myCommandSettingsFactory = commandSettingsFactory; + myHgPathProvider = hgPathProvider; + } + + @NotNull + public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException { + return new HgRepo(myCommandSettingsFactory.forRoot(root), workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); + } + + @NotNull + public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir, @NotNull MercurialProgress progress) throws VcsException { + CommandSettingsFactory settingsFactory = myCommandSettingsFactory.forRoot(root); + return new HgRepo(new FactoryWithProgess(settingsFactory, progress), workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); + } + + + @NotNull + public HgRepo createTempDirRepo(@NotNull HgVcsRoot root) { + return new HgRepo(myCommandSettingsFactory.forRoot(root), myPluginConfig.getTempDir(), + myHgPathProvider.getHgPath(root), root.getAuthSettings()); + } + + + private static class FactoryWithProgess implements CommandSettingsFactory { + private final CommandSettingsFactory myDelegate; + private final MercurialProgress myProgress; + public FactoryWithProgess(@NotNull CommandSettingsFactory delegate, @NotNull MercurialProgress progress) { + myDelegate = delegate; + myProgress = progress; + } + + @NotNull + public CommandSettings create() { + CommandSettings commandSettings = myDelegate.create(); + commandSettings.setProgress(myProgress); + return commandSettings; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgDetector.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,156 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.agent.AgentLifeCycleAdapter; +import jetbrains.buildServer.agent.AgentLifeCycleListener; +import jetbrains.buildServer.agent.BuildAgent; +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommand; +import jetbrains.buildServer.util.EventDispatcher; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +/** + * @author dmitry.neverov + */ +public class HgDetector extends AgentLifeCycleAdapter { + + final static String AGENT_HG_PATH_PROPERTY = "teamcity.hg.agent.path"; + private final static String AGENT_HG_VERSION = "teamcity.hg.version"; + private final static Logger LOG = Logger.getInstance(HgDetector.class.getName()); + private final static HgVersion LEAST_SUPPORTED_VERSION = new HgVersion(1, 5, 2); + private final CommandSettingsFactory myCommandSettingsFactory; + private final List<String> myHgPaths = Arrays.asList("hg"); + + + public HgDetector(@NotNull EventDispatcher<AgentLifeCycleListener> dispatcher, + @NotNull CommandSettingsFactory commandSettingsFactory) { + myCommandSettingsFactory = commandSettingsFactory; + dispatcher.addListener(this); + } + + + @Override + public void beforeAgentConfigurationLoaded(@NotNull final BuildAgent agent) { + BuildAgentConfiguration config = agent.getConfiguration(); + String agentHgPath = config.getConfigurationParameters().get(AGENT_HG_PATH_PROPERTY); + File tmpDir = config.getTempDirectory(); + if (agentHgPath == null) { + HgExec detectedHg = detectHg(tmpDir); + if (detectedHg != null) { + LOG.info("Detect installed mercurial at path " + detectedHg.getPath() + ", provide it as a property " + AGENT_HG_PATH_PROPERTY); + config.addConfigurationParameter(AGENT_HG_PATH_PROPERTY, "hg"); + config.addConfigurationParameter(AGENT_HG_VERSION, detectedHg.getVersion().toString()); + } else { + LOG.info("Cannot detect installed mercurial"); + } + } else { + HgExec hg = detectHgAtPath(tmpDir, agentHgPath, true); + if (hg == null) { + LOG.warn("Cannot run mercurial at path " + agentHgPath); + } else { + if (isCompatible(hg.getVersion())) { + config.addConfigurationParameter(AGENT_HG_VERSION, hg.getVersion().toString()); + } else { + LOG.warn("Mercurial at path " + agentHgPath + " is not compatible with TeamCity"); + } + } + } + } + + + @Nullable + private HgExec detectHg(@NotNull File tmpDir) { + for (String path : myHgPaths) { + HgExec exec = detectHgAtPath(tmpDir, path, false); + if (exec == null) + continue; + if (isCompatible(exec.getVersion())) { + return exec; + } else { + warn("Mercurial version at path " + path + " is " + exec.getVersion() + ", required version is " + LEAST_SUPPORTED_VERSION + "+", false); + } + } + return null; + } + + + @Nullable + private HgExec detectHgAtPath(@NotNull File tmpDir, @NotNull String hgPath, boolean logWarnings) { + try { + HgVersion version = getVersion(hgPath, tmpDir); + return new HgExec(hgPath, version); + } catch (VcsException e) { + warn("Error while trying to get hg version, hg path: " + hgPath, e, logWarnings); + return null; + } + } + + + @NotNull + private HgVersion getVersion(@NotNull String hgPath, @NotNull File workDir) throws VcsException { + return new VersionCommand(myCommandSettingsFactory.create(), hgPath, workDir).call(); + } + + + private void warn(@NotNull final String msg, final boolean logWarnings) { + if (logWarnings) + LOG.warn(msg); + else if (LOG.isDebugEnabled()) + LOG.debug(msg); + } + + private void warn(@NotNull final String msg, @NotNull final Throwable t, final boolean logWarnings) { + if (logWarnings) + LOG.warn(msg, t); + else if (LOG.isDebugEnabled()) + LOG.debug(msg, t); + } + + private boolean isCompatible(@NotNull final HgVersion version) { + return version.isEqualsOrGreaterThan(LEAST_SUPPORTED_VERSION); + } + + + private static class HgExec { + private final String myPath; + private final HgVersion myVersion; + + public HgExec(@NotNull String path, @NotNull HgVersion version) { + myPath = path; + myVersion = version; + } + + @NotNull + public String getPath() { + return myPath; + } + + @NotNull + public HgVersion getVersion() { + return myVersion; + } + } +}
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,143 +1,141 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.agent.BuildProgressLogger; -import jetbrains.buildServer.agent.vcs.AgentVcsSupport; -import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; -import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules; -import jetbrains.buildServer.agent.vcs.UpdatePolicy; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.CheckoutRules; -import jetbrains.buildServer.vcs.IncludeRule; -import jetbrains.buildServer.vcs.VcsException; -import jetbrains.buildServer.vcs.VcsRoot; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; - -public class MercurialAgentSideVcsSupport extends AgentVcsSupport implements UpdateByIncludeRules { - private void updateWorkingDir(final Settings settings, final String version, final BuildProgressLogger logger) throws VcsException { - logger.message("Updating working directory from the local repository copy"); - UpdateCommand uc = new UpdateCommand(settings); - ChangeSet cs = new ChangeSet(version); - uc.setToId(cs.getId()); - uc.execute(); - logger.message("Working directory updated successfully"); - } - - private File cloneRepository(final Settings settings) throws VcsException { - File tempDir; - try { - File parent = FileUtil.createTempDirectory("hg", "clone"); - parent.deleteOnExit(); - tempDir = new File(parent, "hg"); - } catch (IOException e) { - throw new VcsException("Failed to create temp directory: " + e.getLocalizedMessage()); - } - - CloneCommand cc = new CloneCommand(settings); - cc.setDestDir(tempDir.getAbsolutePath()); - - cc.setUpdateWorkingDir(false); - cc.execute(); - return tempDir; - } - - /** - * Moves files from one directory to another with all subdirectories. - * Removes old directory if it became empty. - */ - private static boolean moveDir(File oldDir, File newDir) { - // both old and new directories exist - boolean moveSuccessful = true; - final File[] files = oldDir.listFiles(); - if (files != null) { - for (File file: files) { - if (file.isFile()) { - File destFile = new File(newDir, file.getName()); - destFile.getParentFile().mkdirs(); - if (!file.renameTo(destFile)) { - moveSuccessful = false; - } - } else if (!moveDir(file, new File(newDir, file.getName()))) { - moveSuccessful = false; - } - } - } - - if (moveSuccessful) { - FileUtil.deleteIfEmpty(oldDir); - } - - return moveSuccessful; - } - - @NotNull - @Override - public UpdatePolicy getUpdatePolicy() { - return this; - } - - @NotNull - @Override - public String getName() { - return Constants.VCS_NAME; - } - - public IncludeRuleUpdater getUpdater(@NotNull final VcsRoot vcsRoot, @NotNull final CheckoutRules checkoutRules, @NotNull final String toVersion, @NotNull final File checkoutDirectory, @NotNull final BuildProgressLogger logger) throws VcsException { - return new IncludeRuleUpdater() { - public void process(@NotNull final IncludeRule includeRule, @NotNull final File workingDir) throws VcsException { - if (includeRule.getTo() != null && includeRule.getTo().length() > 0) { - if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) { - throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); - } - } - - Settings settings = new Settings(workingDir, vcsRoot); - settings.setWorkingDir(workingDir); - if (settings.hasCopyOfRepository()) { - // execute pull command - logger.message("Repository in working directory found, start pulling changes"); - PullCommand pc = new PullCommand(settings); - pc.execute(); - logger.message("Changes successfully pulled"); - } else { - // execute clone command - logger.message("No repository in working directory found, start cloning repository to temporary folder"); - File parentDir = cloneRepository(settings); - logger.message("Repository successfully cloned to: " + parentDir.getAbsolutePath()); - logger.message("Moving repository to working directory: " + workingDir.getAbsolutePath()); - if (!moveDir(parentDir, workingDir)) { - File hgDir = new File(workingDir, ".hg"); - if (hgDir.isDirectory()) { - FileUtil.delete(hgDir); - } - throw new VcsException("Failed to move directory content: " + parentDir.getAbsolutePath() + " to: " + workingDir.getAbsolutePath()); - } - - logger.message("Repository successfully moved to working directory: " + workingDir.getAbsolutePath()); - } - updateWorkingDir(settings, toVersion, logger); - } - - public void dispose() throws VcsException { - } - }; - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.vcs.*; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.CheckoutInfo; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.MercurialExtension; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.MercurialExtensionManager; +import jetbrains.buildServer.vcs.*; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; + +public class MercurialAgentSideVcsSupport extends AgentVcsSupport implements UpdateByIncludeRules2 { + + private final AgentPluginConfig myConfig; + private final MirrorManager myMirrorManager; + private final AgentRepoFactory myRepoFactory; + private final MercurialExtensionManager myExtentionManager; + + public MercurialAgentSideVcsSupport(@NotNull AgentPluginConfig pluginConfig, + @NotNull MirrorManager mirrorManager, + @NotNull AgentRepoFactory repoFactory, + @NotNull MercurialExtensionManager extentionManager) { + myConfig = pluginConfig; + myMirrorManager = mirrorManager; + myRepoFactory = repoFactory; + myExtentionManager = extentionManager; + } + + public IncludeRuleUpdater getUpdater(@NotNull final VcsRoot vcsRoot, @NotNull final CheckoutRules checkoutRules, @NotNull final String toVersion, @NotNull final File checkoutDirectory, @NotNull final AgentRunningBuild build, boolean cleanCheckoutRequested) throws VcsException { + MercurialIncludeRuleUpdater updater; + if (myConfig.shareLocalMirrors(build, vcsRoot)) { + updater = new SharingMercurialUpdater(myConfig, myMirrorManager, myRepoFactory, vcsRoot, toVersion, build); + } else { + updater = new MercurialIncludeRuleUpdater(myConfig, myMirrorManager, myRepoFactory, vcsRoot, toVersion, build); + } + registerExtensions(vcsRoot, checkoutRules, updater); + return updater; + } + + @NotNull + @Override + public AgentCheckoutAbility canCheckout(@NotNull VcsRoot vcsRoot, @NotNull CheckoutRules checkoutRules, @NotNull AgentRunningBuild build) { + CheckoutInfo info = new CheckoutInfo(myRepoFactory, new HgVcsRoot(vcsRoot), checkoutRules); + try { + info.getTempDirRepo().version().call(); + } catch (VcsException e) { + return AgentCheckoutAbility.noVcsClientOnAgent(e.getMessage()); + } + + Set<String> targetDirs = new HashSet<>(); + try { + for (IncludeRule rule : checkoutRules.getRootIncludeRules()) { + MercurialIncludeRuleUpdater.checkRuleIsValid(rule); + targetDirs.add(rule.getTo()); + } + } catch (VcsException e) { + return AgentCheckoutAbility.notSupportedCheckoutRules(e.getMessage()); + } + + List<VcsRootEntry> mercurialEntries = getMercurialEntries(build); + if (mercurialEntries.size() > 1) { + for (VcsRootEntry entry : mercurialEntries) { + VcsRoot otherRoot = entry.getVcsRoot(); + if (vcsRoot.equals(otherRoot)) + continue; + for (IncludeRule rule : getOtherRootRules(entry.getCheckoutRules().getRootIncludeRules())) { + if (targetDirs.contains(rule.getTo())) + return AgentCheckoutAbility.canNotCheckout("Cannot checkout VCS root '" + vcsRoot.getName() + "' into the same directory as VCS root '" + otherRoot.getName() + "'"); + } + } + } + + return AgentCheckoutAbility.canCheckout(); + } + + + @NotNull + private List<VcsRootEntry> getMercurialEntries(@NotNull AgentRunningBuild build) { + List<VcsRootEntry> result = new ArrayList<>(); + for (VcsRootEntry entry : build.getVcsRootEntries()) { + if (Constants.VCS_NAME.equals(entry.getVcsRoot().getVcsName())) + result.add(entry); + } + return result; + } + + + @NotNull + private List<IncludeRule> getOtherRootRules(@NotNull List<IncludeRule> rules) { + List<IncludeRule> result = new ArrayList<>(); + for (IncludeRule rule : rules) { + try { + MercurialIncludeRuleUpdater.checkRuleIsValid(rule); + } catch (VcsException e) { + //return empty root rules to skip checks; appropriate cannot checkout reason + //will be returned during otherRoot's canCheckout() call + return Collections.emptyList(); + } + result.add(rule); + } + return result; + } + + + private void registerExtensions(@NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules, @NotNull MercurialIncludeRuleUpdater updater) { + CheckoutInfo info = new CheckoutInfo(myRepoFactory, new HgVcsRoot(root), checkoutRules); + for (MercurialExtension ext :myExtentionManager.getExtensionsForCheckout(info)) { + updater.registerExtension(ext); + } + } + + @NotNull + @Override + public String getName() { + return Constants.VCS_NAME; + } + + @NotNull + @Override + public UpdatePolicy getUpdatePolicy() { + return this; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialBuildLogProgress.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.BuildProgressLogger; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.atomic.AtomicInteger; + +public class MercurialBuildLogProgress implements MercurialProgress { + + private final BuildProgressLogger myLogger; + private final AtomicInteger myBlockMessageCount = new AtomicInteger(0); + private String myPrevMessage; + private int myPrevPercents; + + public MercurialBuildLogProgress(@NotNull BuildProgressLogger logger) { + myLogger = logger; + } + + public void progressStarted(@NotNull String progressMessage) { + myBlockMessageCount.set(0); + myLogger.activityStarted(progressMessage, "CUSTOM_HG_PROGRESS"); + } + + public void reportProgress(@NotNull String progressMessage) { + myBlockMessageCount.incrementAndGet(); + myLogger.message(progressMessage); + } + + public void progressFinished(@NotNull String progressMessage) { + if (myBlockMessageCount.get() == 0) + myLogger.message("");//add an empty message so that the empty block is shown in UI + myLogger.activityFinished(progressMessage, "CUSTOM_HG_PROGRESS"); + } + + public void reportProgress(float percentage, @NotNull String stage) { + if (percentage < 0) { + resetPrevProgress(); + reportProgress(stage); + } else { + int percents = (int) Math.floor(percentage * 100); + if (!isDuplicate(stage, percents)) { + myLogger.message(stage + " " + percents + "%"); + updatePrevProgress(stage, percents); + } + } + } + + private void resetPrevProgress() { + myPrevMessage = null; + myPrevPercents = -1; + } + + private boolean isDuplicate(@NotNull String message, int percents) { + return message.equals(myPrevMessage) && percents == myPrevPercents; + } + + private void updatePrevProgress(@NotNull String message, int percents) { + myPrevMessage = message; + myPrevPercents = percents; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,288 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.BuildProgressLogger; +import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.PullCommand; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.AbandonedTransactionFound; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.WrongSubrepoUrlException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.BeforeWorkingDirUpdateExtension; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.MercurialExtension; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.IncludeRule; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.intellij.openapi.util.io.FileUtil.delete; + +/** + * @author dmitry.neverov + */ +public class MercurialIncludeRuleUpdater implements IncludeRuleUpdater { + + protected final MirrorManager myMirrorManager; + protected final AgentRepoFactory myRepoFactory; + protected final HgVcsRoot myRoot; + private final AuthSettings myAuthSettings; + private final String myToVersion; + private final BuildProgressLogger myLogger; + private final boolean myUseLocalMirrors; + private int myPullTimeout; + private final boolean myUseTraceback; + private final boolean myProfile; + private final List<MercurialExtension> myExtensions = new ArrayList<>(); + protected final MercurialProgress myProgress; + + public MercurialIncludeRuleUpdater(@NotNull AgentPluginConfig pluginConfig, + @NotNull MirrorManager mirrorManager, + @NotNull AgentRepoFactory repoFactory, + @NotNull VcsRoot root, + @NotNull String toVersion, + @NotNull AgentRunningBuild build) { + myMirrorManager = mirrorManager; + myRepoFactory = repoFactory; + myRoot = new HgVcsRoot(root); + myAuthSettings = myRoot.getAuthSettings(); + myToVersion = toVersion; + myLogger = build.getBuildLogger(); + myUseLocalMirrors = pluginConfig.isUseLocalMirrors(build, root); + myPullTimeout = pluginConfig.getPullTimeout(build); + myUseTraceback = pluginConfig.runWithTraceback(build); + myProfile = pluginConfig.runWithProfile(build); + myProgress = new MercurialBuildLogProgress(build.getBuildLogger().getFlowLogger("-1")); + } + + + public void process(@NotNull IncludeRule rule, @NotNull File workingDir) throws VcsException { + try { + checkRuleIsValid(rule); + if (myUseLocalMirrors) + updateLocalMirror(myRoot.getRepository(), myToVersion); + updateRepository(workingDir); + updateWorkingDir(workingDir, myToVersion, myRoot.getRepository()); + } catch (Exception e) { + throwVcsException(e); + } + } + + + public void dispose() throws VcsException { + } + + + public void registerExtension(@NotNull MercurialExtension extention) { + myExtensions.add(extention); + } + + + @NotNull + protected <T extends MercurialExtension> List<T> getExtensions(@NotNull Class<T> extensionClass) { + List<T> extentions = new ArrayList<>(); + for (MercurialExtension e : myExtensions) { + if (extensionClass.isInstance(e)) + extentions.add(extensionClass.cast(e)); + } + return extentions; + } + + + protected void updateLocalMirror(@NotNull String repositoryUrl, @NotNull String revision) throws VcsException, IOException { + File mirrorDir = myMirrorManager.getMirrorDir(repositoryUrl); + HgRepo mirrorRepo = myRepoFactory.createRepo(myRoot, mirrorDir, myProgress); + if (!mirrorRepo.isValidRepository()) { + delete(mirrorDir); + mirrorRepo.init().call(); + } + mirrorRepo.setDefaultPath(myRoot.getRepository()); + mirrorRepo.setTeamCityConfig(myRoot.getCustomHgConfig()); + myLogger.message("Update local mirror of " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl) + " at " + mirrorDir); + if (mirrorRepo.containsRevision(revision)) { + myLogger.message("Local mirror is already up-to-date"); + } else { + PullCommand pull = mirrorRepo.pull().fromRepository(repositoryUrl) + .withTraceback(myUseTraceback) + .withProfile(myProfile) + .withTimeout(myPullTimeout); + try { + pull.call(); + } catch (AbandonedTransactionFound e) { + myLogger.message("Abandoned transaction found, trying to recover"); + mirrorRepo.recover().call(); + pull.call(); + } + } + } + + + protected void updateRepository(@NotNull File workingDir) throws VcsException, IOException { + String repositoryUrl = getDefaultPullUrl(myRoot, myUseLocalMirrors); + HgRepo repo = myRepoFactory.createRepo(myRoot, workingDir, myProgress); + myLogger.message("Update repository " + workingDir.getAbsolutePath()); + disableSharing(workingDir); + if (!repo.isValidRepository()) + repo.init().call(); + repo.setDefaultPath(myRoot.getRepository()); + repo.setTeamCityConfig(myRoot.getCustomHgConfig()); + if (repo.containsRevision(myToVersion)) { + myLogger.message("Repository already contains revision " + myToVersion); + } else { + try { + repo.pull().fromRepository(repositoryUrl) + .withTraceback(myUseTraceback) + .withProfile(myProfile) + .withTimeout(myPullTimeout) + .call(); + } catch (UnrelatedRepositoryException e) { + throw new UnrelatedRepositoryException(myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl), workingDir); + } + } + } + + + private void disableSharing(@NotNull File workingDir) { + File dotHg = new File(workingDir, ".hg"); + File sharedpath = new File(dotHg, "sharedpath"); + if (sharedpath.exists()) + FileUtil.delete(sharedpath); + } + + + private void updateWorkingDir(@NotNull File workingDir, @NotNull String toVersion, @NotNull String repositoryUrl) throws VcsException, IOException { + HgRepo repo = myRepoFactory.createRepo(myRoot, workingDir, myProgress); + List<File> repos = new ArrayList<>(); + updateSubrepositories(repo, toVersion, repositoryUrl, repos); + doUpdateWorkingDir(repo, toVersion); + purge(repos); + } + + private void purge(@NotNull List<File> dirs) throws VcsException { + HgVcsRoot.PurgePolicy purgePolicy = myRoot.getPurgePolicy(); + if (purgePolicy == HgVcsRoot.PurgePolicy.DONT_RUN) + return; + for (File dir : dirs) { + HgRepo repo = myRepoFactory.createRepo(myRoot, dir, myProgress); + repo.purge().withPolicy(purgePolicy).call(); + } + } + + private void updateSubrepositories(@NotNull HgRepo repo, + @NotNull String toVersion, + @NotNull String parentRepositoryUrl, + @NotNull List<File> repoAccumulator) throws VcsException, IOException { + repoAccumulator.add(repo.getWorkingDir()); + if (!repo.hasSubreposAtRevision(toVersion)) + return; + myLogger.message("Process subrepos of " + parentRepositoryUrl); + String workingDirRevision = repo.getWorkingDirRevision(); + Map<String, SubRepo> workingDirSubrepos = repo.getSubrepositories(workingDirRevision); + Map<String, SubRepo> subrepos = repo.getSubrepositories(toVersion); + for (Map.Entry<String, SubRepo> entry : subrepos.entrySet()) { + String path = entry.getKey(); + SubRepo subrepoConfig = entry.getValue(); + myLogger.message("Process subrepoConfig at path " + path + " (url: " + subrepoConfig.url() + ")"); + SubRepo workingDirSubrepo = workingDirSubrepos.get(path); + if (workingDirSubrepo != null && subrepoConfig.hasDifferentUrlThan(workingDirSubrepo)) { + myLogger.message("The url of subrepoConfig was changed between revisions " + workingDirRevision + " and " + toVersion + " , delete the subrepoConfig"); + delete(subrepoConfigDir(repo, subrepoConfig)); + } + HgRepo subrepository = myRepoFactory.createRepo(myRoot, subrepoConfigDir(repo, subrepoConfig), myProgress); + String subrepoUrl; + try { + subrepoUrl = subrepoConfig.resolveUrl(parentRepositoryUrl); + if (myUseLocalMirrors && subrepoConfig.vcsType() == SubRepo.VcsType.hg && !isRelativeUrl(subrepoUrl)) + syncSubrepo(subrepository, subrepoUrl, subrepoConfig.revision()); + } catch (WrongSubrepoUrlException e) { + myLogger.warning("Failed to resolve subrepo url '" + subrepoConfig.url() + "': " + e.getMessage()); + Loggers.VCS.warn("Failed to resolve subrepo url '" + subrepoConfig.url() + "'", e); + subrepoUrl = subrepoConfig.url(); + } + updateSubrepositories(subrepository, subrepoConfig.revision(), subrepoUrl, repoAccumulator); + } + } + + private boolean isRelativeUrl(@NotNull String url) { + return url.startsWith("."); + } + + protected void syncSubrepo(@NotNull HgRepo subrepository, @NotNull String subrepoUrl, @NotNull String subrepoRevision) throws VcsException, IOException { + disableSharing(subrepository.getWorkingDir()); + if (!subrepository.isValidRepository() || !subrepository.containsRevision(subrepoRevision)) { + updateLocalMirror(subrepoUrl, subrepoRevision); + File mirrorDir = myMirrorManager.getMirrorDir(subrepoUrl); + if (!subrepository.isValidRepository()) + subrepository.init().call(); + subrepository.setDefaultPath(subrepoUrl); + subrepository.setTeamCityConfig(myRoot.getCustomHgConfig()); + myLogger.message("Pull from local mirror"); + subrepository.pull().fromRepository(mirrorDir) + .withTraceback(myUseTraceback) + .withProfile(myProfile) + .withTimeout(myPullTimeout) + .call(); + myLogger.message("done"); + } + } + + + private void doUpdateWorkingDir(@NotNull HgRepo repo, @NotNull String revision) throws VcsException { + for (BeforeWorkingDirUpdateExtension e : getExtensions(BeforeWorkingDirUpdateExtension.class)) { + e.call(repo, revision); + } + repo.update().withTraceback(myUseTraceback).withProfile(myProfile).toRevision(revision).call(); + } + + + protected String getDefaultPullUrl(HgVcsRoot root, boolean useLocalMirror) throws IOException { + if (useLocalMirror) { + File mirrorDir = myMirrorManager.getMirrorDir(root.getRepository()); + return mirrorDir.getCanonicalPath(); + } else { + return root.getRepository(); + } + } + + + public static void checkRuleIsValid(IncludeRule includeRule) throws VcsException { + if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) + throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); + } + + + private void throwVcsException(Exception e) throws VcsException { + if (e instanceof VcsException) + throw (VcsException) e; + else + throw new VcsException(e); + } + + private File subrepoConfigDir(@NotNull HgRepo parentRepo, @NotNull SubRepo subrepo) { + return new File(parentRepo.getWorkingDir(), subrepo.path()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SharingMercurialUpdater.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * Updater which uses local mirrors and hg share extension (available in hg 1.3+) + * http://mercurial.selenic.com/wiki/ShareExtension + */ +public class SharingMercurialUpdater extends MercurialIncludeRuleUpdater { + public SharingMercurialUpdater(@NotNull AgentPluginConfig pluginConfig, + @NotNull MirrorManager mirrorManager, + @NotNull AgentRepoFactory repoFactory, + @NotNull VcsRoot root, + @NotNull String toVersion, + @NotNull AgentRunningBuild build) { + super(pluginConfig, mirrorManager, repoFactory, root, toVersion, build); + } + + @Override + protected void updateRepository(@NotNull File workingDir) throws VcsException, IOException { + HgRepo repo = myRepoFactory.createRepo(myRoot, workingDir, myProgress); + if (repo.isEmpty() || !repo.isValidRepository()) + repo.init().call(); + repo.setDefaultPath(myRoot.getRepository()); + repo.setTeamCityConfig(myRoot.getCustomHgConfig()); + + File mirrorHg = getMirrorHg(myRoot.getRepository()); + String sharedPath = readSharedPath(workingDir); + if (mirrorHg.getCanonicalPath().equals(sharedPath)) { + writeRequires(mirrorHg, workingDir); + } else { + writeRequires(mirrorHg, workingDir); + writeSharedPath(mirrorHg, workingDir); + } + } + + @Override + protected void syncSubrepo(@NotNull HgRepo subrepository, @NotNull String subrepoUrl, @NotNull String subrepoRevision) throws VcsException, IOException { + if (subrepository.isEmpty() || !subrepository.isValidRepository()) + subrepository.init().call(); + subrepository.setDefaultPath(subrepoUrl); + subrepository.setTeamCityConfig(myRoot.getCustomHgConfig()); + + if (!subrepository.containsRevision(subrepoRevision)) { + updateLocalMirror(subrepoUrl, subrepoRevision); + File mirrorHg = getMirrorHg(subrepoUrl); + String sharedPath = readSharedPath(subrepository.getWorkingDir()); + if (mirrorHg.getCanonicalPath().equals(sharedPath)) { + writeRequires(mirrorHg, subrepository.getWorkingDir()); + } else { + writeRequires(mirrorHg, subrepository.getWorkingDir()); + writeSharedPath(mirrorHg, subrepository.getWorkingDir()); + } + } + } + + @Nullable + private String readSharedPath(@NotNull File workingDir) throws IOException { + File sharedPath = getSharedPath(workingDir); + if (!sharedPath.exists()) + return null; + return FileUtil.readText(sharedPath); + } + + private void writeSharedPath(@NotNull File mirrorHg, @NotNull File workingDir) throws IOException { + FileUtil.writeToFile(getSharedPath(workingDir), mirrorHg.getCanonicalPath().getBytes(StandardCharsets.UTF_8)); + } + + private void writeRequires(@NotNull File mirrorHg, @NotNull File workingDir) throws IOException { + //Copy .hg/requires from mirror to working dir because it could be created by + //an older version or mercurial. When shared repositories are used this can + //lead to errors, because mercurial command is trying to work with .hg in + //mirrors as if it was of a newer version. + File mirrorRequires = new File(mirrorHg, "requires"); + File workingDirRequires = new File(new File(workingDir, ".hg"), "requires"); + FileUtil.copy(mirrorRequires, workingDirRequires); + FileUtil.writeToFile(workingDirRequires, "shared\n".getBytes(), true); + } + + @NotNull + private File getSharedPath(File workingDir) { + return new File(new File(workingDir, ".hg"), "sharedpath"); + } + + @NotNull + private File getMirrorHg(@NotNull String repositoryUrl) { + File mirrorDir = myMirrorManager.getMirrorDir(repositoryUrl); + return new File(mirrorDir, ".hg"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/BeforeWorkingDirUpdateExtension.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +public interface BeforeWorkingDirUpdateExtension extends MercurialExtension { + void call(@NotNull HgRepo repo, @NotNull String revision) throws VcsException; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/CheckoutInfo.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentRepoFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.CheckoutRules; +import org.jetbrains.annotations.NotNull; + +public class CheckoutInfo { + private final AgentRepoFactory myRepoFactory; + private final HgVcsRoot myRoot; + private final CheckoutRules myRules; + + public CheckoutInfo(@NotNull AgentRepoFactory repoFactory, + @NotNull HgVcsRoot root, + @NotNull CheckoutRules rules) { + myRepoFactory = repoFactory; + myRoot = root; + myRules = rules; + } + + @NotNull + public CheckoutRules getCheckoutRules() { + return myRules; + } + + @NotNull + public HgVcsRoot getRoot() { + return myRoot; + } + + @NotNull + public HgRepo getTempDirRepo() { + return myRepoFactory.createTempDirRepo(getRoot()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/MercurialExtension.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,20 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext; + +public interface MercurialExtension { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/MercurialExtensionManager.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class MercurialExtensionManager { + + private final List<MercurialExtensionProvider> myProviders = new ArrayList<>(); + + public void registerExtentionFactory(@NotNull MercurialExtensionProvider provider) { + myProviders.add(provider); + } + + @NotNull + public List<MercurialExtension> getExtensionsForCheckout(@NotNull CheckoutInfo info) { + List<MercurialExtension> extensions = new ArrayList<>(); + for (MercurialExtensionProvider provider : myProviders) { + MercurialExtension ext = provider.getExtentionForCheckout(info); + if (ext != null) + extensions.add(ext); + } + return extensions; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/MercurialExtensionProvider.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface MercurialExtensionProvider { + + @Nullable + MercurialExtension getExtentionForCheckout(@NotNull CheckoutInfo info); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/impl/SparseCheckoutProvider.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,156 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.impl; + +import com.intellij.openapi.util.text.StringUtil; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandResult; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.*; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.FileRule; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class SparseCheckoutProvider implements MercurialExtensionProvider { + + private static final HgVersion MIN_SPARSE_CHECKOUT_VERSION = new HgVersion(3, 0, 0); + + public SparseCheckoutProvider(@NotNull MercurialExtensionManager extentionManager) { + extentionManager.registerExtentionFactory(this); + } + + @Nullable + public MercurialExtension getExtentionForCheckout(@NotNull CheckoutInfo info) { + if (sparseIsAvailable(info)) { + return new SparseCheckout(info.getCheckoutRules()); + } else { + return new UndoSparseCheckout(); + } + } + + + private boolean sparseIsAvailable(@NotNull CheckoutInfo info) { + if (info.getCheckoutRules().getExcludeRules().isEmpty()) + return false; + try { + HgVersion version = info.getTempDirRepo().version().call(); + if (!version.isEqualsOrGreaterThan(MIN_SPARSE_CHECKOUT_VERSION)) { + Loggers.VCS.info("The sparse checkout is not supported in the mercurial version " + version.toString()); + return false; + } + CommandResult result = info.getTempDirRepo().runCommand("help", "extensions"); + boolean enabledExtensions = false; + for (String line : StringUtil.splitByLines(result.getRawStdout())) { + if (line.trim().equals("enabled extensions:")) { + enabledExtensions = true; + continue; + } + if (line.trim().equals("disabled extensions:")) { + return false; + } + if (enabledExtensions) { + List<String> words = StringUtil.getWordsIn(line.trim()); + if (words.isEmpty()) + continue; + if (words.get(0).equals("sparse")) { + Loggers.VCS.info("Sparse extension is enabled"); + return true; + } + } + } + return true; + } catch (VcsException e) { + //log + return false; + } + } + + + private static class SparseCheckout implements BeforeWorkingDirUpdateExtension { + private final CheckoutRules myRules; + private SparseCheckout(@NotNull CheckoutRules rules) { + myRules = rules; + } + + public void call(@NotNull HgRepo repo, @NotNull String revision) throws VcsException { + String currentConfig = readSparseContent(repo.getWorkingDir()); + String newConfig = getSparseContentFromRules(); + if (currentConfig.equals(newConfig)) + return; + writeSparseConfig(repo.getWorkingDir(), newConfig); + repo.runCommand("sparse", "--refresh"); + } + + private void writeSparseConfig(@NotNull File workingDir, @NotNull String sparseContent) throws VcsException { + try { + FileUtil.writeToFile(getSparseConfig(workingDir), sparseContent.getBytes(StandardCharsets.UTF_8), false); + } catch (IOException e) { + Loggers.VCS.warn("Error while writing .hg/sparse, will not do a sparse checkout", e); + } + } + + @NotNull + private String getSparseContentFromRules() { + StringBuilder sparse = new StringBuilder(); + sparse.append("[exclude]\n"); + for (FileRule<?> rule : myRules.getExcludeRules()) { + sparse.append(rule.getFrom()).append("\n"); + } + return sparse.toString(); + } + + @NotNull + private String readSparseContent(@NotNull File workingDir) { + File sparseConfig = getSparseConfig(workingDir); + if (!sparseConfig.exists()) + return ""; + try { + return FileUtil.readText(sparseConfig); + } catch (IOException e) { + Loggers.VCS.warn("Error while reading .hg/sparse, assume it was empty", e); + return ""; + } + } + } + + + private static class UndoSparseCheckout implements BeforeWorkingDirUpdateExtension { + public void call(@NotNull HgRepo repo, @NotNull String revision) throws VcsException { + File workingDir = repo.getWorkingDir(); + File sparseConfig = getSparseConfig(workingDir); + if (sparseConfig.exists()) { + Loggers.VCS.info("Remove sparse extension config and reset working directory state"); + FileUtil.delete(sparseConfig); + FileUtil.delete(new File(new File(workingDir, ".hg"), "dirstate")); + } + } + } + + + private static File getSparseConfig(@NotNull File workingDir) { + return new File(new File(workingDir, ".hg"), "sparse"); + } +}
--- a/mercurial-common/mercurial-common.iml Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/mercurial-common.iml Thu Aug 06 12:15:36 2020 +0300 @@ -1,15 +1,16 @@ <?xml version="1.0" encoding="UTF-8"?> <module relativePaths="true" type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="false"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false"> <output url="file://$MODULE_DIR$/classes" /> <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> </content> - <orderEntry type="inheritedJdk" /> + <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="library" exported="" name="TeamCityAPI-common" level="project" /> <orderEntry type="library" exported="" name="IDEA-openapi" level="project" /> + <orderEntry type="library" name="jdom" level="project" /> + <orderEntry type="library" name="commons-codec-1.4" level="project" /> </component> -</module> - +</module> \ No newline at end of file
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,28 +1,49 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.vcs.VcsRoot; - -public interface Constants { - String VCS_NAME = "mercurial"; - String REPOSITORY_PROP = "repositoryPath"; - String BRANCH_NAME_PROP = "branchName"; - String HG_COMMAND_PATH_PROP = "hgCommandPath"; - String SERVER_CLONE_PATH_PROP = "serverClonePath"; - String USERNAME = "username"; - String PASSWORD = VcsRoot.SECURE_PROPERTY_PREFIX + "password"; -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.VcsRoot; + +public interface Constants { + String VCS_NAME = "mercurial"; + String REPOSITORY_PROP = "repositoryPath"; + String BRANCH_NAME_PROP = "branchName"; + String HG_COMMAND_PATH_PROP = "hgCommandPath"; + String HG_PATH_ENV = "TEAMCITY_HG_PATH"; + String SERVER_CLONE_PATH_PROP = "serverClonePath"; + String USERNAME = "username"; + String PASSWORD = VcsRoot.SECURE_PROPERTY_PREFIX + "password"; + String USER_FOR_TAG = "tagUsername"; + String DETECT_SUBREPO_CHANGES = "detectSubrepoChanges"; + String USE_TAGS_AS_BRANCHES = "useTagsAsBranches"; + String INCLUDE_SUBREPOS_IN_PATCH = "includeSubreposInPatch"; + String USE_ARCHIVE_FOR_PATCH = "useArchiveForPatch"; + String HG_EXTENSIONS = "hg.extensions"; + String HG_COMMANDLINE_VIA_FILE = "hg.pass.commandline.via.file"; + String PURGE_POLICY = "purgePolicy"; + String GLOBAL_DETECT_SUBREPO_CHANGES = "teamcity.hg.detectSubrepoChanges"; + String IGNORE_MISSING_DEFAULT_BRANCH = "IGNORE_MISSING_DEFAULT_BRANCH"; + String CUSTOM_HG_CONFIG_PROP = "customHgConfig"; + String TEAMCITY_HG_CONFIG_FILE_NAME = "teamcity"; + String USE_AGENT_MIRRORS = "useSharedMirrors"; + + String SHOW_CUSTOM_CLONE_PATH = "teamcity.hg.showCustomClonePath"; + String CUSTOM_CLONE_PATH_ENABLED = "teamcity.hg.customClonePathEnabled"; + String CUSTOM_CLONE_PATH_WHITELIST = "teamcity.hg.customClonePathWhitelist"; + String CUSTOM_CACHES_DIR = "teamcity.hg.customCachesDir"; + String CUSTOM_SERVER_HG_PATH_WHITELIST = "teamcity.hg.customServerHgPathWhitelist"; + String CUSTOM_HG_CONFIG_ENABLED = "teamcity.hg.customConfigEnabled"; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import jetbrains.buildServer.util.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; + +/** + * @author dmitry.neverov + */ +public final class HgFileUtil { + + private final static String TEMP_DIR_PREFIX = "hg"; + private final static Object ourTmpDirLock = new Object(); + + private HgFileUtil() { + } + + /** + * Create a temp dir with short name + * @return created dir + * @throws IOException in case of I/O error + */ + @NotNull + public static File createTempDir() throws IOException { + File parentDir = new File(FileUtil.getTempDirectory()); + return createTempDir(parentDir); + } + + @NotNull + public static File createTempDir(@NotNull final File parentDir) throws IOException { + //noinspection ResultOfMethodCallIgnored + parentDir.mkdirs(); + + int suffix = 0; + File dir; + while (true) { + suffix++; + String tmpDirName = TEMP_DIR_PREFIX + suffix; + dir = new File(parentDir, tmpDirName); + if (dir.exists()) + continue; + + synchronized (ourTmpDirLock) { + try { + if (!dir.createNewFile()) + continue; + } catch (IOException e) { + //workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6325169 + if (SystemInfo.isWindows && "Access is denied".equals(e.getMessage())) + continue; + throw e; + } + if (!dir.delete()) + continue; + if (!dir.mkdir()) + continue; + } + return dir; + } + } + + + public static void deleteDir(@Nullable final File dir, @NotNull final Logger logger) { + if (dir == null) + return; + FileUtil.symlinkAwareDelete(dir); + if (dir.exists()) + logger.warn("Cannot delete directory " + dir.getAbsolutePath()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathProvider.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public interface HgPathProvider { + + String getHgPath(@NotNull HgVcsRoot root); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,396 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir; +import static jetbrains.buildServer.util.FileUtil.isEmptyDir; + +/** +* @author dmitry.neverov +*/ +public class HgRepo { + + protected final CommandSettingsFactory myCommandSettingsFactory; + protected final File myWorkingDir; + protected final String myHgPath; + protected final AuthSettings myAuthSettings; + protected final Map<String, Map<String, SubRepo>> mySubreposCache = new HashMap<>(); + + public HgRepo(@NotNull CommandSettingsFactory commandSettingsFactory, + @NotNull File workingDir, + @NotNull String hgPath, + @NotNull AuthSettings authSettings) { + myCommandSettingsFactory = commandSettingsFactory; + myWorkingDir = workingDir; + myHgPath = hgPath; + myAuthSettings = authSettings; + } + + public PullCommand pull() { + return new PullCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public PushCommand push() { + return new PushCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public CloneCommand doClone() { + return new CloneCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public IdentifyCommand id() { + return new IdentifyCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public Init init() { + return new Init(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public LogCommand log() { + return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + @NotNull + public CommitsAndMountPointsCommand logSubstates() throws VcsException { + return new CommitsAndMountPointsCommand(this, myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public UpdateCommand update() { + return new UpdateCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public BranchCommand branch() { + return new BranchCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public BranchesCommand branches() { + return new BranchesCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public BookmarksCommand bookmarks() { + return new BookmarksCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public UpdateBookmarkCommand updateBookmark() { + return new UpdateBookmarkCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public TagsCommand tags() { + return new TagsCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public Map<String, String> getBranchRevisions(boolean includeBookmarks, boolean includeTags) throws VcsException { + Map<String, String> revisions = new HashMap<>(); + if (includeTags) + revisions.putAll(tags().call()); + if (includeBookmarks && version().call().isEqualsOrGreaterThan(BookmarksCommand.REQUIRED_HG_VERSION)) + revisions.putAll(bookmarks().call()); + revisions.putAll(branches().call()); + return revisions; + } + + public StatusCommand status() { + return new StatusCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public TagCommand tag() { + return new TagCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public CatCommand cat() { + return new CatCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public ArchiveCommand archive() { + return new ArchiveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); + } + + public VersionCommand version() { + return new VersionCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public ParentsCommand parents() { + return new ParentsCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public MergeCommand merge() { + return new MergeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public ResolveCommand resolve() { + return new ResolveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public CommitCommand commit() { + return new CommitCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public AddRemoveCommand addRemove() { + return new AddRemoveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public RecoverCommand recover() { + return new RecoverCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + public String path() { + return myWorkingDir.getAbsolutePath(); + } + + public File getWorkingDir() { + return myWorkingDir; + } + + public boolean isEmpty() { + return isEmptyDir(myWorkingDir); + } + + public boolean isBookmark(@NotNull String branch) throws VcsException { + if (branches().call().keySet().contains(branch)) + return false; + return bookmarks().call().keySet().contains(branch); + } + + public void resetBookmarks() { + File dotHg = new File(getWorkingDir(), ".hg"); + FileUtil.delete(new File(dotHg, "bookmarks")); + FileUtil.delete(new File(dotHg, "bookmarks.current")); + } + + public PurgeCommand purge() { + return new PurgeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + + @NotNull + public CommandResult runCommand(@NotNull String command, @NotNull String... args) throws VcsException { + return new FreeStyleCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, command, args).call(); + } + + public String getHgPath() { + return myHgPath; + } + + @NotNull + public List<String> listFiles(@NotNull String revision) throws VcsException { + List<FileStatus> fileStatuses = status() + .fromRevision(revision) + .toRevision(revision) + .hideStatus() + .showAllFiles() + .call(); + List<String> files = new ArrayList<>(fileStatuses.size()); + for (FileStatus fileStatus : fileStatuses) + files.add(fileStatus.getPath()); + return files; + } + + @NotNull + public String getWorkingDirRevision() throws VcsException { + List<String> workingDirParents = parents().call(); + if (workingDirParents.isEmpty()) + return LogCommand.ZERO_PARENT_SHORT_ID;//'hg id' shows zeroid when a working dir has no parents + //if a working dir is in an uncommitted merge state, choose the first parent + return workingDirParents.get(0); + } + + public boolean containsRevision(@NotNull String revision) { + return containsRevision(new ChangeSet(revision)); + } + + public boolean containsRevision(@NotNull ChangeSet cset) { + try { + id().revision(cset).inLocalRepository().call(); + return true; + } catch (VcsException e) { + return false; + } + } + + public boolean isValidRepository() { + // need better way to check that repository copy is ok + return myWorkingDir.isDirectory() && new File(myWorkingDir, ".hg").isDirectory(); + } + + public void setDefaultPath(@NotNull String defaultPath) throws VcsException { + if (defaultPath.contains("\n") || defaultPath.contains("\r")) + throw new VcsException("Newline in repository url '" + defaultPath + "'"); + try { + File hgrc = new File(new File(myWorkingDir, ".hg"), "hgrc"); + String content = "%include " + Constants.TEAMCITY_HG_CONFIG_FILE_NAME + "\n\n[paths]\ndefault = " + defaultPath; + FileUtil.writeFileAndReportErrors(hgrc, content); + } catch (IOException e) { + throw new VcsException(e); + } + } + + public void setTeamCityConfig(@NotNull String configContent) throws VcsException { + try { + File teamcityConfig = new File(new File(myWorkingDir, ".hg"), Constants.TEAMCITY_HG_CONFIG_FILE_NAME); + FileUtil.writeFileAndReportErrors(teamcityConfig, configContent); + } catch (IOException e) { + throw new VcsException(e); + } + } + + public boolean hasSubreposAtRevision(@NotNull String revision) { + return !getSubrepositories(new ChangeSet(revision)).isEmpty(); + } + + public boolean hasSubreposAtRevision(@NotNull ChangeSet cset) { + return !getSubrepositories(cset).isEmpty(); + } + + public Map<String, SubRepo> getSubrepositories(@NotNull String revision) { + return getSubrepositories(new ChangeSet(revision)); + } + + public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String revision) throws VcsException { + if (containsSubrepoConfigChange(revision)) { + List<String> parents = parents().ofRevision(revision).call(); + return getSubrepoConfigChanges(revision, parents); + } + return emptyList(); + } + + public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull ChangeSet cset) { + if (containsSubrepoConfigChange(cset)) { + List<String> parents = new ArrayList<>(); + for (ChangeSetRevision p : cset.getParents()) { + parents.add(p.getId()); + } + return getSubrepoConfigChanges(cset.getId(), parents); + } + return emptyList(); + } + + public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String fromRevision, @NotNull String toRevision) { + return getSubrepoConfigChanges(toRevision, asList(fromRevision)); + } + + public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String revision, @NotNull List<String> parentRevisions) { + Map<String, SubRepo> curSubrepos = getSubrepositories(revision); + List<Map<String, SubRepo>> prevSubrepos = new ArrayList<>(); + for (String parentRevision : parentRevisions) { + prevSubrepos.add(getSubrepositories(parentRevision)); + } + return getSubrepoConfigChanges(revision, prevSubrepos, curSubrepos); + + } + + private List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String mainRepoRevision, + @NotNull List<Map<String, SubRepo>> prevSubrepos, + @NotNull Map<String, SubRepo> curSubrepos) { + List<HgSubrepoConfigChange> configChanges = new ArrayList<>(); + for (Map.Entry<String, SubRepo> e : curSubrepos.entrySet()) { + String path = e.getKey(); + SubRepo curSubrepo = e.getValue(); + List<SubRepo> prevs = new ArrayList<>(); + for (Map<String, SubRepo> prev : prevSubrepos) { + SubRepo prevSubrepo = prev.remove(path); + if (prevSubrepo == null) //no subrepo at this path in previous revision + continue; + if (prevSubrepo.equals(curSubrepo)) //subrepo configuration doesn't change since previous revision + continue; + prevs.add(prevSubrepo); + } + configChanges.add(new HgSubrepoConfigChange(mainRepoRevision, e.getKey(), prevs, curSubrepo)); + } + for (Map<String, SubRepo> prev : prevSubrepos) { + for (Map.Entry<String, SubRepo> e : prev.entrySet()) { + configChanges.add(new HgSubrepoConfigChange(mainRepoRevision, e.getKey(), e.getValue(), null)); + } + } + return configChanges; + } + + private boolean containsSubrepoConfigChange(@NotNull ChangeSet cset) { + for (FileStatus f : cset.getModifiedFiles()) { + if (containsSubrepoConfigChange(f)) + return true; + } + return false; + } + + private boolean containsSubrepoConfigChange(@NotNull String revision) throws VcsException { + List<FileStatus> changedFiles = status() + .fromRevision(revision) + .toRevision(revision) + .showAllFiles() + .call(); + for (FileStatus f : changedFiles) { + if (containsSubrepoConfigChange(f)) + return true; + } + return false; + } + + private boolean containsSubrepoConfigChange(@NotNull FileStatus f) { + return f.getPath().equals(".hgsubstate"); + } + + //path->subrepo + @NotNull + public Map<String, SubRepo> getSubrepositories(@NotNull final ChangeSet cset) { + final String revId = cset.getId(); + + Map<String, SubRepo> subrepos = mySubreposCache.get(revId); + if (subrepos != null) { + return new HashMap<>(subrepos); + } + + File catDir = null; + final CatCommand cc = cat().setRevId(revId).files(asList(".hgsub", ".hgsubstate")).checkForFailure(false); + try { + catDir = cc.call(); + subrepos = HgSubs.readSubrepositories(new File(catDir, ".hgsub"), new File(catDir, ".hgsubstate")); + mySubreposCache.put(revId, subrepos); + return new HashMap<>(subrepos); + } catch (VcsException e) { + return emptyMap(); + } finally { + deleteDir(catDir, Loggers.VCS); + } + } + + @Override + public String toString() { + return myWorkingDir.getAbsolutePath(); + } + + @NotNull + public static String shortId(@NotNull final String s) { + if (s.length() > 12) + return s.substring(0, 12); + return s; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepoFactory.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public interface HgRepoFactory { + + @NotNull + HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgSubrepoConfigChange.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; + +/** + * A change in subrepo configuration + */ +public class HgSubrepoConfigChange { + + private final String myMainRepoRevision; + private final String myPath; + private final SubRepo myCurrent; + private final List<SubRepo> myPrevious; + + public HgSubrepoConfigChange(@NotNull String mainRepoRevision, + @NotNull String path, + @Nullable SubRepo previous, + @Nullable SubRepo current) { + this(mainRepoRevision, path, previous != null ? asList(previous) : new ArrayList<>(), current); + } + + public HgSubrepoConfigChange(@NotNull String mainRepoRevision, + @NotNull String path, + @NotNull List<SubRepo> previous, + @Nullable SubRepo current) { + myMainRepoRevision = mainRepoRevision; + myPath = path; + myPrevious = previous; + myCurrent = current; + } + + @NotNull + public String getMainRepoRevision() { + return myMainRepoRevision; + } + + @NotNull + public String getPath() { + return myPath; + } + + @NotNull + public List<SubRepo> getPrevious() { + return myPrevious; + } + + public SubRepo getCurrent() { + return myCurrent; + } + + public boolean subrepoRemoved() { + return myCurrent == null && !myPrevious.isEmpty(); + } + + public boolean subrepoAdded() { + return myCurrent != null && myPrevious.isEmpty(); + } + + public boolean subrepoUrlChanged() { + if (myCurrent == null) + return false; + if (myPrevious.isEmpty()) + return false; + for (SubRepo sr : myPrevious) { + if (!myCurrent.url().equals(sr.url())) + return true; + } + return false; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgSubs.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.util.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +import static java.util.Collections.emptyMap; + +/** + * Created 13.01.14 19:51 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class HgSubs { + + @NotNull + public static Map<String, SubRepo> readSubrepositories(@NotNull final File hgsub, + @NotNull final File hgsubstate) { + if (!hgsub.exists() || !hgsubstate.exists()) { + return emptyMap(); + } + + final Map<String, String> path2repo; + final Map<String, String> path2revision; + try { + path2repo = readHgsub(hgsub); + path2revision = readHgsubstate(hgsubstate); + } catch (IOException e) { + return emptyMap(); + } + + return readSubrepositories(path2repo, path2revision); + } + + @NotNull + public static Map<String, SubRepo> readSubrepositories(@Nullable final String hgsubText, + @Nullable final String hgsubstateText) { + + if (hgsubstateText == null || hgsubText == null) return emptyMap(); + + return readSubrepositories( + readHgsub(Arrays.asList(StringUtil.splitByLines(hgsubText))), + readHgsubstate(Arrays.asList(StringUtil.splitByLines(hgsubstateText))) + ); + } + + @NotNull + private static Map<String, SubRepo> readSubrepositories(@NotNull final Map<String, String> path2repo, + @NotNull final Map<String, String> path2revision) { + final Map<String, SubRepo> result = new HashMap<>(); + for (Map.Entry<String, String> entry : path2repo.entrySet()) { + final String path = entry.getKey(); + final String url = entry.getValue(); + final String revision = path2revision.get(path); + if (revision != null) + result.put(path, new SubRepo(path, url, revision)); + } + return result; + } + + @NotNull + /*returns map: relative path -> repository url */ + private static Map<String, String> readHgsub(@NotNull final File hgsub) throws IOException { + return readHgsub(FileUtil.readFile(hgsub)); + } + + @NotNull + /*returns map: relative path -> repository url */ + private static Map<String, String> readHgsub(@NotNull final Collection<String> lines) { + Map<String, String> result = new HashMap<>(); + for (String line : lines) { + String[] parts = line.split(" = "); + if (parts.length == 2) + result.put(parts[0], parts[1]); + } + return result; + } + + + @NotNull + /*returns map: relative path -> revision */ + private static Map<String, String> readHgsubstate(@NotNull final File hgsubstate) throws IOException { + return readHgsubstate(FileUtil.readFile(hgsubstate)); + } + + @NotNull + /*returns map: relative path -> revision */ + private static Map<String, String> readHgsubstate(@NotNull final Collection<String> lines) { + final Map<String, String> result = new HashMap<>(); + for (String line : lines) { + String[] parts = line.split(" "); + if (parts.length == 2) + result.put(parts[1], parts[0]); + } + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersion.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,126 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ParseHgVersionException; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class HgVersion implements Comparable<HgVersion> { + + private static final String PREFIX = "Mercurial Distributed SCM (version "; + + private final int myMajor; + private final int myMinor; + private final int myThird; + + + public HgVersion(int major, int minor, int third) { + myMajor = major; + myMinor = minor; + myThird = third; + } + + + public static HgVersion parse(@NotNull final String version) throws ParseHgVersionException { + Parser p = new Parser(version); + if (!p.skipString(PREFIX)) + throw new ParseHgVersionException(version); + int major = p.readInt(); + p.skipString("."); + int minor = p.readInt(); + int third = p.skipString(".") ? p.readInt() : 0; + return new HgVersion(major, minor, third); + } + + + public boolean isEqualsOrGreaterThan(HgVersion other) { + return compareTo(other) >= 0; + } + + + public boolean isLessThan(@NotNull HgVersion other) { + return compareTo(other) < 0; + } + + + @Override + public String toString() { + return myMajor + "." + myMinor + "." + myThird; + } + + @Override + public boolean equals(Object o) { + return (o instanceof HgVersion) && this.compareTo((HgVersion) o) == 0; + } + + @Override + public int hashCode() { + int result = myMajor; + result = 31 * result + myMinor; + result = 31 * result + myThird; + return result; + } + + public int compareTo(HgVersion other) { + int d = myMajor - other.myMajor; + if (d != 0) + return d; + + d = myMinor - other.myMinor; + if (d != 0) + return d; + + return myThird - other.myThird; + } + + + private static final class Parser { + + private final String myString; + private int myIndex = 0; + + Parser(@NotNull String string) { + myString = string; + } + + + boolean skipString(String str) { + if (myIndex == myString.length() || myIndex + str.length() > myString.length()) + return false; + String substr = myString.substring(myIndex, myIndex + str.length()); + if (substr.equals(str)) { + myIndex = myIndex + str.length(); + return true; + } else { + return false; + } + } + + + int readInt() { + int result = 0; + while (myIndex < myString.length() && Character.isDigit(myString.codePointAt(myIndex))) { + result = result * 10 + Character.digit(myString.codePointAt(myIndex), 10); + myIndex++; + } + return result; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialClasspathTemplate.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +import static com.intellij.openapi.util.io.FileUtil.createTempFile; +import static com.intellij.openapi.util.io.FileUtil.delete; + +/** +* Created 25.02.14 11:29 +* +* @author Eugene Petrenko (eugene.petrenko@jetbrains.com) +*/ +public class MercurialClasspathTemplate implements MercurialTemplate { + private final String myResourcePath; + private final String myTmpFileSuffix; + + public MercurialClasspathTemplate(@NotNull final String resourcePath, + @NotNull final String tmpFileSuffix) { + myResourcePath = resourcePath; + myTmpFileSuffix = tmpFileSuffix; + } + + @NotNull + public <T> T withTemplate(@NotNull final WithTemplate<T> action) throws VcsException { + //TODO: we may pack plugin and use jetbrains.buildServer.web.openapi.PluginDescriptor.getPluginRoot() + //TODO: to get path to existing file + final File template = copyTemplate(); + try { + return action.action(template); + } finally { + delete(template); + } + } + + private File copyTemplate() throws VcsException { + try { + final File template = createTempFile("teamcity", myTmpFileSuffix); + FileUtil.copyResource(getClass(), myResourcePath, template); + return template; + } catch (IOException e) { + throw new VcsException("Cannot create mercurial log template", e); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialProgress.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +public interface MercurialProgress { + + void progressStarted(@NotNull String progressMessage); + + void progressFinished(@NotNull String progressMessage); + + void reportProgress(@NotNull String progressMessage); + + void reportProgress(float percentage, @NotNull String stage); + + MercurialProgress NO_OP = new MercurialProgress() { + public void progressStarted(@NotNull String progressMessage) { + } + public void progressFinished(@NotNull String progressMessage) { + } + public void reportProgress(@NotNull String progressMessage) { + } + public void reportProgress(float percentage, @NotNull String stage) { + } + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialTemplate.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Created 25.02.14 11:51 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public interface MercurialTemplate { + @NotNull + <T> T withTemplate(@NotNull WithTemplate<T> action) throws VcsException; + + interface WithTemplate<T> { + @NotNull + T action(@NotNull final File template) throws VcsException; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsOperationProgress.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.VcsOperationProgress; +import org.jetbrains.annotations.NotNull; + +public class MercurialVcsOperationProgress implements MercurialProgress { + + private final VcsOperationProgress myProgress; + private String myPrevMessage; + private int myPrevPercents; + + public MercurialVcsOperationProgress(@NotNull VcsOperationProgress progress) { + myProgress = progress; + } + + public void progressStarted(@NotNull String progressMessage) { + reportProgress(progressMessage); + } + + public void progressFinished(@NotNull String progressMessage) { + reportProgress(progressMessage); + } + + public void reportProgress(@NotNull String progressMessage) { + myProgress.reportProgress(progressMessage); + } + + public void reportProgress(float percentage, @NotNull String stage) { + if (percentage < 0) { + resetPrevProgress(); + myProgress.reportProgress(stage); + } else { + int percents = (int) Math.floor(percentage * 100); + if (!isDuplicate(stage, percents)) { + myProgress.reportProgress(stage + " " + percents + "%"); + updatePrevProgress(stage, percents); + } + } + } + + private void resetPrevProgress() { + myPrevMessage = null; + myPrevPercents = -1; + } + + private boolean isDuplicate(@NotNull String message, int percents) { + return message.equals(myPrevMessage) && percents == myPrevPercents; + } + + private void updatePrevProgress(@NotNull String message, int percents) { + myPrevMessage = message; + myPrevPercents = percents; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManager.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * @author dmitry.neverov + */ +public interface MirrorManager { + + /** + * Get directory of local mirror repository for specified url, if directory is not exists it is created + * @param url url of interest + * @return see above + */ + @NotNull + File getMirrorDir(@NotNull final String url); + + /** + * Get all local mirror repository dirs + * @return see above + */ + @NotNull + List<File> getMirrors(); + + long getLastUsedTime(@NotNull final File mirrorDir); + + /** + * Forget specified dir. After call to this method with non-empty dir, + * all urls which were mapped to this dir will be mapped to another. + * If dir is empty, subsequent call getMirrorDir(dir) will return the + * same dir. + * + * @param dir dir of interest + */ + void forgetDir(@NotNull final File dir); + + @NotNull + Map<String, File> getMappings(); + + void lockDir(@NotNull File dir); + + void unlockDir(@NotNull File dir); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManagerImpl.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,386 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.util.Hash; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static jetbrains.buildServer.util.FileUtil.isEmptyDir; + +/** + * Manages local mirrors of remote repositories. + * Each unique url get unique local mirror. Each mirror is used for one url only. + * @author dmitry.neverov + */ +public final class MirrorManagerImpl implements MirrorManager { + + private static Logger LOG = Logger.getInstance(MirrorManagerImpl.class.getName()); + private static final String MIRROR_DIR_PREFIX = "hg_"; + private static final String MAPPING_FILE_NAME = "map"; + + private final ReadWriteLock myLock = new ReentrantReadWriteLock(); + private final File myRootDir; + /*Only one thread read or write to this file, it is protected by myLock.writeLock()*/ + private final File myMappingFile; + /*Protected by myLock*/ + private final Map<String, File> myMirrors = new HashMap<>(); + private HashCalculator myHash = new StandartHash(); + + private final ConcurrentMap<String, Lock> myDirLocks = new ConcurrentHashMap<>(); + + public MirrorManagerImpl(@NotNull PluginConfig config) { + myRootDir = config.getCachesDir(); + myMappingFile = new File(myRootDir, MAPPING_FILE_NAME); + readMappingFromFile(); + } + + + /** + * Get directory of local mirror repository for specified url, if directory is not exists it is created + * @param url url of interest + * @return see above + */ + @NotNull + public File getMirrorDir(@NotNull final String url) { + File result = getMirrorDirWithLock(url); + if (result == null) { + result = createDirFor(url); + } + updateLastUsedTime(result); + return result; + } + + + /** + * Get all local mirror repository dirs + * @return see above + */ + @NotNull + public List<File> getMirrors() { + myLock.readLock().lock(); + try { + return new ArrayList<>(myMirrors.values()); + } finally { + myLock.readLock().unlock(); + } + } + + + @NotNull + public Map<String, File> getMappings() { + myLock.readLock().lock(); + try { + return new HashMap<>(myMirrors); + } finally { + myLock.readLock().unlock(); + } + } + + public void lockDir(@NotNull final File dir) { + lockFor(dir).lock(); + } + + public void unlockDir(@NotNull final File dir) { + lockFor(dir).unlock(); + } + + private Lock lockFor(final File dir) { + String path = dir.getAbsolutePath(); + Lock lock = myDirLocks.get(path); + if (lock == null) { + lock = new ReentrantLock(); + Lock curLock = myDirLocks.putIfAbsent(path, lock); + if (curLock != null) + lock = curLock; + } + return lock; + } + + /** + * Forget specified dir. After call to this method with non-empty dir, + * all urls which were mapped to this dir will be mapped to another. + * If dir is empty, subsequent call getMirrorDir(dir) will return the + * same dir. + * + * @param dir dir of interest + */ + public void forgetDir(@NotNull final File dir) { + myLock.writeLock().lock(); + try { + removeMappingsToDir(dir); + saveMappingToFile(); + } finally { + myLock.writeLock().unlock(); + } + } + + private void removeMappingsToDir(@NotNull final File dir) { + Set<String> keysToRemove = getUrlsMappedToDir(dir); + for (String key : keysToRemove) { + myMirrors.remove(key); + } + } + + private Set<String> getUrlsMappedToDir(@NotNull final File dir) { + Set<String> urlsMappedToDir = new HashSet<>(); + for (Map.Entry<String, File> entry : myMirrors.entrySet()) { + File f = entry.getValue(); + if (f.equals(dir)) + urlsMappedToDir.add(entry.getKey()); + } + return urlsMappedToDir; + } + + + //for tests only + void setHashCalculator(HashCalculator hash) { + myHash = hash; + } + + + private File createDirFor(String url) { + File result; + myLock.writeLock().lock(); + try { + File mirrorDir = getUniqueDir(url); + result = saveMappingIfAbsent(url, mirrorDir); + } finally { + myLock.writeLock().unlock(); + } + if (!result.exists()) { + result.mkdirs(); + } + return result; + } + + + private File getMirrorDirWithLock(String url) { + myLock.readLock().lock(); + try { + return myMirrors.get(url); + } finally { + myLock.readLock().unlock(); + } + } + + + //should be called with myLock.writeLock() held + private File saveMappingIfAbsent(String url, File mirrorDir) { + File existing = myMirrors.get(url); + if (existing != null) { + return existing; + } else { + myMirrors.put(url, mirrorDir); + saveMappingToFile(); + return mirrorDir; + } + } + + + private File getUniqueDir(String url) { + myLock.readLock().lock(); + try { + String dirName = MIRROR_DIR_PREFIX + hash(normalize(url)); + File result = PathUtil.getCanonicalFile(new File(myRootDir, dirName)); + while (isUsedForOtherUrl(result, url) || !isEmptyDir(result)) { + dirName = MIRROR_DIR_PREFIX + hash(result.getName()); + result = PathUtil.getCanonicalFile(new File(myRootDir, dirName)); + } + return result; + } finally { + myLock.readLock().unlock(); + } + } + + + private boolean isUsedForOtherUrl(File repositoryDir, String url) { + myLock.readLock().lock(); + try { + for (Map.Entry<String, File> mirror : myMirrors.entrySet()) { + String mirrorUrl = mirror.getKey(); + File mirrorDir = mirror.getValue(); + if (mirrorDir.equals(repositoryDir) && !mirrorUrl.equals(url)) { + return true; + } + } + return false; + } finally { + myLock.readLock().unlock(); + } + } + + + private String hash(String value) { + return String.valueOf(myHash.calc(value)); + } + + + private static String normalize(final String path) { + String normalized = PathUtil.normalizeSeparator(path); + if (path.endsWith("/")) { + return normalized.substring(0, normalized.length()-1); + } + return normalized; + } + + + private void readMappingFromFile() { + myLock.writeLock().lock(); + try { + LOG.debug("Parse mapping file " + myMappingFile.getAbsolutePath()); + for (String line : readLines()) { + int separatorIndex = line.lastIndexOf(" = "); + if (separatorIndex == -1) { + if (!line.equals("")) + LOG.warn("Cannot parse mapping '" + line + "', skip it."); + } else { + String url = line.substring(0, separatorIndex); + String dirName = line.substring(separatorIndex + 3); + File repositoryDir = PathUtil.getCanonicalFile(new File(myRootDir, dirName)); + if (isUsedForOtherUrl(repositoryDir, url)) { + LOG.error("Skip mapping " + line + ": " + dirName + " is used for url other than " + url); + } else { + myMirrors.put(url, PathUtil.getCanonicalFile(new File(myRootDir, dirName))); + } + } + } + } finally { + myLock.writeLock().unlock(); + } + } + + /*Should be called with myLock.writeLock() held*/ + private List<String> readLines() { + if (myMappingFile.exists()) { + try { + return FileUtil.readFile(myMappingFile); + } catch (IOException e) { + LOG.error("Error while reading a mapping file at " + myMappingFile.getAbsolutePath() + " starting with empty mapping", e); + return new ArrayList<>(); + } + } else { + LOG.debug("No mapping file found at " + myMappingFile.getAbsolutePath() + " starting with empty mapping"); + File parentDir = myMappingFile.getParentFile(); + if (!parentDir.exists() && !parentDir.mkdirs()) { + LOG.error("Cannot create local mirrors dir at " + parentDir.getAbsolutePath()); + } else { + try { + if (!myMappingFile.createNewFile()) + LOG.warn("Someone else creates a mapping file " + myMappingFile.getAbsolutePath() + ", will use it"); + } catch (IOException e) { + LOG.error("Cannot create a mapping file at " + myMappingFile.getAbsolutePath(), e); + } + } + return new ArrayList<>(); + } + } + + + private void saveMappingToFile() { + myLock.writeLock().lock(); + try { + StringBuilder sb = new StringBuilder(); + for (Map.Entry<String, File> mirror : myMirrors.entrySet()) { + String url = mirror.getKey(); + String dir = mirror.getValue().getName(); + sb.append(url).append(" = ").append(dir).append("\n"); + } + FileUtil.writeFile(myMappingFile, sb.toString()); + } finally { + myLock.writeLock().unlock(); + } + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + myLock.readLock().lock(); + try { + Iterator<Map.Entry<String, File>> iter = myMirrors.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry<String, File> entry = iter.next(); + sb.append("[").append(entry.getKey()).append("]").append("->").append(entry.getValue().getAbsolutePath()); + if (iter.hasNext()) + sb.append("\n"); + } + } finally { + myLock.readLock().unlock(); + } + return sb.toString(); + } + + public long getLastUsedTime(@NotNull final File mirrorDir) { + File dotHg = new File(mirrorDir, ".hg"); + File timestamp = new File(dotHg, "timestamp"); + if (timestamp.exists()) { + try { + List<String> lines = FileUtil.readFile(timestamp); + if (lines.isEmpty()) + return mirrorDir.lastModified(); + else + return Long.parseLong(lines.get(0)); + } catch (IOException e) { + return mirrorDir.lastModified(); + } + } else { + return mirrorDir.lastModified(); + } + } + + private void updateLastUsedTime(@NotNull final File dir) { + File dotHg = new File(dir, ".hg"); + //create timestamp only if .hg exist, otherwise subsequent clone in this directory will + //fail since directory is not empty + if (!dotHg.exists()) + return; + + lockDir(dir); + try { + File timestamp = new File(dotHg, "timestamp"); + if (!timestamp.exists()) + timestamp.createNewFile(); + FileUtil.writeFileAndReportErrors(timestamp, String.valueOf(System.currentTimeMillis())); + } catch (IOException e) { + LOG.error("Error while updating timestamp in " + dir.getAbsolutePath(), e); + } finally { + unlockDir(dir); + } + } + + final static class StandartHash implements HashCalculator { + public long calc(String value) { + return Hash.calc(value); + } + } + + public interface HashCalculator { + long calc(String value); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OS.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.serverSide.TeamCityProperties; + +/** + * Created 27.01.14 17:21 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class OS { + private static final int COMMAND_LINE_LIMIT = _COMMAND_LINE_LIMIT(); + + private static int _COMMAND_LINE_LIMIT() { + final String OS_NAME = System.getProperty("os.name").toLowerCase(); + ///http://partmaps.org/era/unix/arg-max.html + if (!OS_NAME.contains("windows")) return 128 * 1024 - 1; //128kb + + //http://support.microsoft.com/kb/830473/en-us + if (OS_NAME.matches("windows\\s+(2000|xp|nt)")) { + return 2047; + } + + return 8191; + } + + public static int getMaxCommandLineSize() { + return TeamCityProperties.getInteger("teamcity.mercurial.maxCommandLineSize", COMMAND_LINE_LIMIT); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,37 +1,37 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; - -public class PathUtil { - @NotNull - public static String normalizeSeparator(@NotNull String repPath) { - return repPath.replace('\\', '/'); - } - - @NotNull - public static File getCanonicalFile(@NotNull File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - return file.getAbsoluteFile(); - } - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +public class PathUtil { + @NotNull + public static String normalizeSeparator(@NotNull String repPath) { + return repPath.replace('\\', '/'); + } + + @NotNull + public static File getCanonicalFile(@NotNull File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PluginConfig.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public interface PluginConfig { + + @NotNull + File getCachesDir(); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SubRepo.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,169 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.WrongSubrepoUrlException; +import jetbrains.buildServer.util.FileUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +/** +* @author dmitry.neverov +*/ +public class SubRepo { + private final String myPath; + private final String myUrl; + private final String myRevision; + private final VcsType myVcsType; + + public SubRepo(@NotNull String path, @NotNull String url, @NotNull String revision) { + myPath = path; + myRevision = revision; + + if (url.startsWith("[svn]")) { + myVcsType = VcsType.svn; + myUrl = url.substring(5).trim(); + } else if (url.startsWith("[git]")) { + myVcsType = VcsType.git; + myUrl = url.substring(5).trim(); + } else { + myVcsType = VcsType.hg; + myUrl = url.trim(); + } + } + + @NotNull + public String path() { + return myPath; + } + + @NotNull + public String url() { + return myUrl; + } + + @NotNull + public String revision() { + return HgRepo.shortId(myRevision); + } + + public String fullRevision() { + return myRevision; + } + + @NotNull + public VcsType vcsType() { + return myVcsType; + } + + public boolean hasDifferentUrlThan(@NotNull SubRepo other) { + return !myUrl.equals(other.url()); + } + + @NotNull + public String resolveUrl(@NotNull final String parentRepoUrl) throws WrongSubrepoUrlException { + try { + URI parentURI = parentRepoUrl.endsWith("/") ? new URI(parentRepoUrl) : new URI(parentRepoUrl + "/"); + URI subrepoAbsUrl = parentURI.resolve(url()); + if (isSsh(subrepoAbsUrl) && isPathFromRoot(parentURI)) + return getUrlWithPathFromRoot(subrepoAbsUrl); + return subrepoAbsUrl.toString(); + } catch (Exception e) { + File parentRepoDir = new File(parentRepoUrl); + if (parentRepoDir.isDirectory()) {//handle windows paths + try { + return FileUtil.resolvePath(parentRepoDir, FileUtil.normalizeSeparator(url())).getCanonicalPath(); + } catch (IOException e1) { + throw new WrongSubrepoUrlException(parentRepoUrl, url(), e); + } + } + throw new WrongSubrepoUrlException(parentRepoUrl, url(), e); + } + } + + private boolean isSsh(@NotNull URI uri) { + return "ssh".equals(uri.getScheme()); + } + + private boolean isPathFromRoot(@NotNull URI uri) { + return uri.getPath() != null && uri.getPath().startsWith("//"); + } + + @NotNull + private String getUrlWithPathFromRoot(@NotNull URI uri) throws URISyntaxException { + return new URI(uri.getScheme(), + uri.getUserInfo(), + uri.getHost(), + uri.getPort(), + "/" + uri.getPath(), + uri.getQuery(), + uri.getFragment()).toString(); + } + + @Override + public String toString() { + return myPath + " = " + myUrl + "#" + myRevision; + } + + public enum VcsType { + hg(Constants.VCS_NAME), git("jetbrains.git"), svn("svn") + ; + + private final String myVcsPluginName; + + VcsType(@NotNull String vcsPluginName) { + myVcsPluginName = vcsPluginName; + } + + @NotNull + public String getVcsPluginName() { + return myVcsPluginName; + } + + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof SubRepo)) + return false; + + SubRepo subRepo = (SubRepo) o; + + if (!myPath.equals(subRepo.myPath)) + return false; + if (!myRevision.equals(subRepo.myRevision)) + return false; + if (!myUrl.equals(subRepo.myUrl)) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = myPath.hashCode(); + result = 31 * result + myUrl.hashCode(); + result = 31 * result + myRevision.hashCode(); + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AddRemoveCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class AddRemoveCommand extends BaseCommand { + + public AddRemoveCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir) { + super(commandSettings, hgPath, workingDir); + } + + public void call() throws VcsException { + MercurialCommandLine cmd = createCommandLine(); + cmd.addParameter("addremove"); + runCommand(cmd); + } + + @NotNull + @Override + protected String getDescription() { + return "hg addremove"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2018 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. + */ + +/* + * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class ArchiveCommand extends AuthCommand { + private File myDestination; + private String myToId; + private String myType = "files"; + private List<String> myIncludeRules = new ArrayList<>(); + + public ArchiveCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir, + @NotNull AuthSettings authSettings) { + super(commandSettings, hgPath, workingDir, authSettings); + } + + public ArchiveCommand destination(@NotNull File destination) { + myDestination = destination; + return this; + } + + public ArchiveCommand revision(@NotNull ChangeSet cset) { + myToId = cset.getId(); + return this; + } + + public ArchiveCommand type(@NotNull String type) { + myType = type; + return this; + } + + public boolean addIncludePathRule(@NotNull String rule) { + final MercurialCommandLine cmd = createCmd(); + + String pathRule = "path:" + rule; + final int cmdSize = cmd.getCommandLineLength(); + if (cmdSize + pathRule.length() + 3 + (myIncludeRules.isEmpty() ? 0 : "-I ".length()) > myCommandSettings.getMaxCommandLineSize()) { + return false; + } + + myIncludeRules.add(pathRule); + return true; + } + + public void call() throws VcsException { + if (myDestination == null) + throw new IllegalStateException("Destination dir must be specified"); + MercurialCommandLine cli = createCmd(); + + runCommand(cli, myCommandSettings.setFailWhenStderrNotEmpty(true)); + deleteHgArchival(); + } + + @NotNull + private MercurialCommandLine createCmd() { + final MercurialCommandLine cli = createCommandLine(); + + addHttpAuthParams(cli); + + cli.addParameter("archive"); + cli.addParameter("-t"); + cli.addParameter(myType); + cli.addParameter("-r"); + + if (myToId != null) { + cli.addParameter(myToId); + } else { + cli.addParameter("tip"); + } + + for (String include : myIncludeRules) { + cli.addParameter("-I"); + cli.addParameter(include); + } + cli.addParameter(myDestination.getAbsolutePath()); + + return cli; + } + + /** + * hg archive generates .hg_archival.txt, delete it since original repository do not have such file + */ + private void deleteHgArchival() { + if (myDestination == null) + throw new IllegalStateException("Destination dir must be specified"); + File hg_arhival = new File(myDestination, ".hg_archival.txt"); + if (hg_arhival.exists()) + FileUtil.delete(hg_arhival); + } + + @NotNull + @Override + protected String getDescription() { + return "hg archive -r " + (myToId != null ? myToId : "tip"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AuthCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Command that may require authentication + */ +public class AuthCommand extends VcsRootCommand { + + public AuthCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir, + @NotNull AuthSettings authSettings) { + super(commandSettings, hgPath, workingDir, authSettings); + } + + @NotNull + protected MercurialCommandLine createCL() { + MercurialCommandLine cmd = super.createCL(); + cmd.addParameters("--config", "ui.interactive=False"); + return cmd; + } + + protected void addHttpAuthParams(@NotNull final MercurialCommandLine cmd) { + if (myAuthSettings.getUsername() == null || myAuthSettings.getPassword() == null) + return; + cmd.addParameters("--config", "auth.tc.prefix=*"); + cmd.addParameters("--config", "auth.tc.username=" + myAuthSettings.getUsername()); + cmd.addParameters("--config", "auth.tc.password=" + myAuthSettings.getPassword()); + cmd.addParameters("--config", "auth.tc.schemes=http https"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AuthSettings.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,182 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.serverSide.TeamCityProperties; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.net.*; +import java.util.HashSet; +import java.util.Set; + +import static com.intellij.openapi.util.text.StringUtil.isEmpty; +import static java.util.Arrays.asList; + +/** + * @author dmitry.neverov + */ +public class AuthSettings { + + private final static Set<String> AUTH_PROTOS = new HashSet<>(asList("http", "https", "ssh")); + private final String myUsername; + private final String myPassword; + + public AuthSettings() { + this(null, null); + } + + public AuthSettings(@Nullable String username, @Nullable String password) { + myUsername = username; + myPassword = password; + } + + public String getUsername() { + return myUsername; + } + + public String getPassword() { + return myPassword; + } + + public String getRepositoryUrlWithCredentials(@NotNull String repositoryUrl) { + String preparedUrl = escapeUnsafeChars(repositoryUrl); + if (isRequireCredentials(preparedUrl)) { + if (containsCredentials(preparedUrl)) + return preparedUrl; + try { + return createURLWithCredentials(preparedUrl); + } catch (MalformedURLException e) { + Loggers.VCS.warn("Error while parsing url " + preparedUrl, e); + } + return preparedUrl; + } else { + return preparedUrl; + } + } + + @NotNull + private String escapeUnsafeChars(@NotNull String repositoryUrl) { + if (!TeamCityProperties.getBooleanOrTrue("teamcity.mercurial.identifyCommand.escapeUnsafeChars")) return repositoryUrl; + + StringBuilder res = new StringBuilder(); + + for (char c: repositoryUrl.toCharArray()) { + switch (c) { + case '"': + res.append("%22"); + break; + case '\'': + res.append("%27"); + break; + case '`': + res.append("%60"); + break; + case ' ': + res.append("%20"); + break; + case ';': + res.append("%3B"); + break; + default: + res.append(c); + } + } + + return res.toString(); + } + + public String getRepositoryUrlWithHiddenPassword(@NotNull String repositoryUrl) { + if (isEmpty(myPassword)) + return repositoryUrl; + return repositoryUrl.replace(myPassword, "******"); + } + + private boolean isRequireCredentials(@NotNull String repositoryUrl) { + for (String scheme : AUTH_PROTOS) { + if (repositoryUrl.startsWith(scheme + ":")) + return true; + } + return false; + } + + private boolean containsCredentials(final String repositoryUrl) { + try { + URL url = new URL(null, repositoryUrl, new FakeStreamHandler()); + String userInfo = url.getUserInfo(); + return userInfo != null && userInfo.contains(":"); + } catch (MalformedURLException e) { + return false; + } + } + + private String createURLWithCredentials(String originalUrl) throws MalformedURLException { + String userInfo = createUserInfo(); + if (!isEmpty(userInfo)) { + URL url = new URL(null, originalUrl, new FakeStreamHandler()); + return url.getProtocol() + "://" + + userInfo + "@" + + url.getHost() + + (url.getPort() != -1 ? ":" + url.getPort() : "") + + url.getFile() + + (url.getRef() != null ? url.getRef() : ""); + } else { + return originalUrl; + } + } + + private String createUserInfo() { + String userInfo = ""; + if (!isEmpty(myUsername)) { + userInfo += myUsername; + if (!isEmpty(myPassword)) { + userInfo += ":" + myPassword; + } + } + return getEscapedUserInfo(userInfo); + } + + private static String getEscapedUserInfo(String userInfo) { + try { + URI uri = new URI("http", userInfo, "somewhere.com", 80, "", "", ""); + String escapedURI = uri.toASCIIString(); + int from = "http://".length(); + int to = escapedURI.indexOf("somewhere.com") - 1; + String escapedUserInfo = escapedURI.substring(from, to); + escapedUserInfo = escapedUserInfo.replaceAll("&", "%26"); + return escapedUserInfo; + } catch (URISyntaxException e) { + assert false; + } + return userInfo; + } + + @NotNull + public static String escapePassword(@NotNull String password) { + String escaped = getEscapedUserInfo("user:" + password); + return escaped.substring(5); + } + + private static class FakeStreamHandler extends URLStreamHandler { + @Override + protected URLConnection openConnection(URL u) throws IOException { + throw new UnsupportedOperationException(); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,82 +1,107 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.util.StringUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.Set; - -/** - * @author pavel - */ -public class BaseCommand { - private Settings mySettings; - private String myWorkDirectory; - - public BaseCommand(@NotNull final Settings settings) { - mySettings = settings; - myWorkDirectory = settings.getLocalRepositoryDir().getAbsolutePath(); - } - - public Settings getSettings() { - return mySettings; - } - - /** - * Sets new working directory, by default working directory is taken from the Settings#getLocalRepositoryDir - * @param workDirectory work dir - */ - public void setWorkDirectory(final String workDirectory) { - myWorkDirectory = workDirectory; - } - - protected GeneralCommandLine createCommandLine() { - GeneralCommandLine cli = new GeneralCommandLine(); - cli.setExePath(getSettings().getHgCommandPath()); - cli.setWorkDirectory(myWorkDirectory); - cli.setPassParentEnvs(true); - return cli; - } - - protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { - return CommandUtil.runCommand(cli, getPrivateData()); - } - - protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException { - return CommandUtil.runCommand(cli, executionTimeout, getPrivateData()); - } - - protected void failIfNotEmptyStdErr(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException { - if (!StringUtil.isEmpty(res.getStderr())) { - CommandUtil.commandFailed(cli.getCommandLineString(), res); - } - } - - protected void failIfNonZeroExitCode(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException { - if (res.getExitCode() != 0) { - CommandUtil.commandFailed(cli.getCommandLineString(), res); - } - } - - public Set<String> getPrivateData() { - return Collections.singleton(mySettings.getPassword()); - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Set; + +import static java.util.Collections.emptySet; + +/** + * @author pavel + */ +public class BaseCommand { + + protected final CommandSettings myCommandSettings; + private final String myHgPath; + private final File myWorkDirectory; + + public BaseCommand(@NotNull final CommandSettings commandSettings, + @NotNull final String hgPath, + @NotNull final File workingDir) { + myCommandSettings = commandSettings; + myHgPath = hgPath; + myWorkDirectory = workingDir; + } + + public File getWorkDirectory() { + return myWorkDirectory; + } + + @NotNull + protected MercurialCommandLine createCommandLine() { + MercurialCommandLine cli = createCL(); + cli.setWorkDirectory(myWorkDirectory.getAbsolutePath()); + return cli; + } + + @NotNull + protected MercurialCommandLine createCL() { + final MercurialCommandLine cl = new MercurialCommandLine(getPrivateData()); + cl.setExePath(myHgPath); + cl.setEnvParams(myCommandSettings.getHgEnv()); + cl.setDescription(getDescription()); + + //include global arguments if any + cl.addParameters(myCommandSettings.getGlobalArguments()); + + return cl; + } + + @NotNull + protected final CommandResult runCommand(@NotNull MercurialCommandLine cli) throws VcsException { + return runCommand(cli, myCommandSettings); + } + + @NotNull + protected final CommandResult runCommand(@NotNull final MercurialCommandLine cli, + @NotNull final CommandSettings commandSettings) throws VcsException { + + if (!myCommandSettings.getUseCommandlineViaFileWrapper()) { + cli.logCommandStarted(commandSettings.getProgress()); + try { + return CommandUtil.runCommand(cli, commandSettings.setPrivateData(getPrivateData())); + } finally { + cli.logCommandFinished(commandSettings.getProgress()); + } + } + + return CommandUtil.runWrappedCommand(cli, commandSettings); + } + + protected void setupExtensionsFromResource(@NotNull final MercurialCommandLine cli, + @NotNull final File tempDir, + @NotNull final String commandPy) throws VcsException{ + CommandUtil.setupExtensionsFromResource(cli, tempDir, commandPy); + } + + @NotNull + protected Set<String> getPrivateData() { + return emptySet(); + } + + protected String getHgPath() { + return myHgPath; + } + + @NotNull + protected String getDescription() { + return ""; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BookmarksCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; +import org.jetbrains.annotations.NotNull; +import java.io.File; + + +public class BookmarksCommand extends BranchesCommand { + + //hg 2.4 automatically pulls bookmarks + public static final HgVersion REQUIRED_HG_VERSION = new HgVersion(2, 4, 0); + + public BookmarksCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir, + @NotNull AuthSettings authSettings) { + super(commandSettings, hgPath, workingDir, authSettings); + } + + @NotNull + @Override + protected String getBranchesCommand() { + return "bookmarks"; + } + + @NotNull + @Override + protected String getDescription() { + return "hg bookmarks"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class BranchCommand extends BaseCommand { + + private String myBranch; + + public BranchCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir) { + super(commandSettings, hgPath, workingDir); + } + + @NotNull + public BranchCommand name(String branch) { + myBranch = branch; + return this; + } + + public void call() throws VcsException { + if (myBranch == null) + return; + MercurialCommandLine cmd = createCommandLine(); + cmd.addParameter("branch"); + cmd.addParameter(myBranch); + runCommand(cmd); + } + + @NotNull + @Override + protected String getDescription() { + if (myBranch == null) + return ""; + return "hg branch " + myBranch; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,59 +1,73 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -/** - * @author Pavel.Sher - * Date: 26.10.2008 - */ -public class BranchesCommand extends BaseCommand { - public BranchesCommand(@NotNull final Settings settings) { - super(settings); - } - - /** - * Returns map of branch name to latest changeset in that branch - * @return see above - * @throws jetbrains.buildServer.vcs.VcsException if error occurs - */ - public Map<String, ChangeSet> execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("branches"); - ExecResult res = runCommand(cli); - String stdout = res.getStdout(); - Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); - Pattern branchPattern = Pattern.compile("(.*)[\\s]+([0-9]+:[A-Za-z0-9]+).*"); - for (String line: stdout.split("[\r\n]+")) { - Matcher matcher = branchPattern.matcher(line); - if (matcher.matches()) { - String branchName = matcher.group(1).trim(); - String changeId = matcher.group(2).trim(); - result.put(branchName, new ChangeSet(changeId)); - } - } - return result; - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Pavel.Sher + * Date: 26.10.2008 + */ +public class BranchesCommand extends VcsRootCommand { + + public BranchesCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir, + @NotNull AuthSettings authSettings) { + super(commandSettings, hgPath, workingDir, authSettings); + } + + /** + * Returns map of branch name to latest changeset in that branch + * @return see above + * @throws jetbrains.buildServer.vcs.VcsException if error occurs + */ + public Map<String, String> call() throws VcsException { + MercurialCommandLine cli = createCommandLine(); + cli.addParameter(getBranchesCommand()); + CommandResult res = runCommand(cli); + String stdout = res.getRawStdout(); + Map<String, String> result = new HashMap<>(); + Pattern branchPattern = Pattern.compile("(.*)[\\s]+([0-9]+:[A-Za-z0-9]+).*"); + for (String line: stdout.split("[\r\n]+")) { + Matcher matcher = branchPattern.matcher(line); + if (matcher.matches()) { + String branchName = matcher.group(1).trim(); + String changeId = matcher.group(2).trim(); + result.put(branchName, new ChangeSet(changeId).getId()); + } + } + return result; + } + + @NotNull + protected String getBranchesCommand() { + return "branches"; + } + + @NotNull + @Override + protected String getDescription() { + return "hg branches"; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,83 +1,152 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -public class CatCommand extends BaseCommand { - private String myRevId; - private final static int MAX_CMD_LEN = 900; - - public CatCommand(@NotNull final Settings settings) { - super(settings); - } - - public void setRevId(final String revId) { - myRevId = revId; - } - - public File execute(List<String> relPaths) throws VcsException { - File tempDir; - try { - tempDir = FileUtil.createTempDirectory("mercurial", "catresult"); - } catch (IOException e) { - throw new VcsException("Unable to create temporary directory"); - } - for (String path: relPaths) { - final File parentFile = new File(tempDir, path).getParentFile(); - if (!parentFile.isDirectory() && !parentFile.mkdirs()) { - throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath()); - } - } - - Queue<String> paths = new LinkedList<String>(relPaths); - while (!paths.isEmpty()) { - GeneralCommandLine cli = createCommandLine(tempDir); - int cmdSize = cli.getCommandLineString().length(); - - do { - String path = paths.poll(); - cli.addParameter(path); - cmdSize += path.length(); - } while (cmdSize < MAX_CMD_LEN && !paths.isEmpty()); - - runCommand(cli); - } - - return tempDir; - } - - private GeneralCommandLine createCommandLine(final File tempDir) { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("cat"); - cli.addParameter("-o"); - cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p"); - if (myRevId != null) { - cli.addParameter("-r"); - cli.addParameter(myRevId); - } - return cli; - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static java.util.Collections.singletonList; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir; + +public class CatCommand extends AuthCommand { + private String myRevId; + + private List<String> myRelativePaths = new ArrayList<>(); + private boolean myCheckForFailure = true; + + public CatCommand(@NotNull CommandSettings commandSettings, + @NotNull String hgPath, + @NotNull File workingDir, + @NotNull AuthSettings authSettings) { + super(commandSettings, hgPath, workingDir, authSettings); + } + + @NotNull + public CatCommand files(@NotNull String relativePath) { + myRelativePaths = singletonList(relativePath); + return this; + } + + @NotNull + public CatCommand files(@NotNull List<String> relativePaths) { + myRelativePaths = relativePaths; + return this; + } + + @NotNull + public CatCommand setRevId(final String revId) { + myRevId = revId; + return this; + } + + @NotNull + public CatCommand atRevision(@NotNull ChangeSet cset) { + myRevId = cset.getId(); + return this; + } + + @NotNull + public CatCommand checkForFailure(boolean doCheckForFailure) { + myCheckForFailure = doCheckForFailure; + return this; + } + + @NotNull + public File call() throws VcsException { + File tempDir = null; + try { + tempDir = createTmpDir(); + createDirectories(myRelativePaths, tempDir); + catFiles(myRelativePaths, myCheckForFailure, tempDir); + return tempDir; + } catch (VcsException e) { + deleteDir(tempDir, Loggers.VCS); + throw e; + } + } + + @NotNull + private File createTmpDir() throws VcsException { + try { + return HgFileUtil.createTempDir(); + } catch (IOException e) { + throw new VcsException("Unable to create temporary directory", e); + } + } + + private void createDirectories(@NotNull final List<String> relPaths, @NotNull final File tempDir) throws VcsException { + for (String path: relPaths) { + File parentFile = new File(tempDir, path).getParentFile(); + if (!parentFile.isDirectory() && !parentFile.mkdirs()) + throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath()); + } + } + + private void catFiles(@NotNull final List<String> relPaths, + final boolean checkFailure, + @NotNull final File tempDir) throws VcsException { + final Queue<String> paths = new LinkedList<>(relPaths); + while (!paths.isEmpty()) { + MercurialCommandLine cli = createCommandLine(tempDir); + int cmdSize = cli.getCommandLineLength() + 42; + + List<String> pathsForDescription = new ArrayList<>(2); + do { + String path = paths.poll(); + if (pathsForDescription.size() < 2) + pathsForDescription.add(path); + cli.addParameter(path); + cmdSize += path.length() + 3; //quotes + space + } while (cmdSize < myCommandSettings.getMaxCommandLineSize() && !paths.isEmpty()); + + cli.setDescription(getDescription(pathsForDescription)); + runCommand(cli, myCommandSettings.setCheckForFailure(checkFailure)); + } + } + + @NotNull + private String getDescription(List<String> pathsForDescription) { + StringBuilder description = new StringBuilder(); + description.append("hg cat -r ").append(myRevId).append(" "); + for (String p : pathsForDescription) { + description.append(p).append(" "); + } + return description.toString(); + } + + @NotNull + private MercurialCommandLine createCommandLine(@NotNull final File tempDir) { + final MercurialCommandLine cli = createCommandLine(); + addHttpAuthParams(cli); + cli.addParameter("cat"); + cli.addParameter("-o"); + cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p"); + if (myRevId != null) { + cli.addParameter("-r"); + cli.addParameter(myRevId); + } + return cli; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,112 +1,127 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Represents Mercurial change set - */ -public class ChangeSet extends ChangeSetRevision { - @NotNull private String myUser; - @NotNull private Date myTimestamp; - private String myDescription; - private boolean myContainsFiles; - private List<ChangeSetRevision> myParents; - - public ChangeSet(final int revNumber, @NotNull final String id) { - super(revNumber, id); - } - - /** - * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) - * @param fullVersion full changeset version as reported by hg log command - */ - public ChangeSet(@NotNull final String fullVersion) { - super(fullVersion); - } - - public void setUser(@NotNull final String user) { - myUser = user; - } - - public void setTimestamp(@NotNull final Date timestamp) { - myTimestamp = timestamp; - } - - public void setDescription(final String description) { - myDescription = description; - } - - public void setContainsFiles(final boolean containsFiles) { - myContainsFiles = containsFiles; - } - - public void addParent(@NotNull ChangeSetRevision rev) { - if (myParents == null) { - myParents = new ArrayList<ChangeSetRevision>(); - } - myParents.add(rev); - } - - /** - * Returns user who made changeset - * @return user who made changeset - */ - @NotNull - public String getUser() { - return myUser; - } - - /** - * Returns changeset timestamp - * @return changeset timestamp - */ - @NotNull - public Date getTimestamp() { - return myTimestamp; - } - - /** - * Returns changeset summary specified by user - * @return changeset summary - */ - public String getDescription() { - return myDescription; - } - - /** - * Returns parrents of this change set, or null if there were no parents. - * @return see above - */ - @Nullable - public List<ChangeSetRevision> getParents() { - return myParents; - } - - /** - * Returns true if this change has changed files - * @return see above - */ - public boolean containsFiles() { - return myContainsFiles; - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot.DEFAULT_BRANCH_NAME; + +/** + * Represents Mercurial change set + */ +public class ChangeSet extends ChangeSetRevision { + @NotNull private String myUser; + @NotNull private Date myTimestamp; + private String myDescription; + private String myBranch = DEFAULT_BRANCH_NAME; + private List<ChangeSetRevision> myParents = new ArrayList<>(); + private List<FileStatus> myModifiedFiles = new ArrayList<>(); + + public ChangeSet(final int revNumber, @NotNull final String id) { + super(revNumber, id); + } + + /** + * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) + * @param fullVersion full changeset version as reported by hg log command + */ + public ChangeSet(@NotNull final String fullVersion) { + super(fullVersion); + } + + public void setUser(@NotNull final String user) { + myUser = user; + } + + public void setTimestamp(@NotNull final Date timestamp) { + myTimestamp = timestamp; + } + + public void setDescription(final String description) { + myDescription = description; + } + + public void addParent(@NotNull ChangeSetRevision rev) { + myParents.add(rev); + } + + /** + * Returns user who made changeset + * @return user who made changeset + */ + @NotNull + public String getUser() { + return myUser; + } + + /** + * Returns changeset timestamp + * @return changeset timestamp + */ + @NotNull + public Date getTimestamp() { + return myTimestamp; + } + + /** + * Returns changeset summary specified by user + * @return changeset summary + */ + public String getDescription() { + return myDescription; + } + + /** + * Returns parrents of this change set + * @return see above + */ + @NotNull + public List<ChangeSetRevision> getParents() { + return myParents; + } + + /** + * Check if changeset is initial changeset (has no parents) + * @return true if changeset is initial changeset + */ + public boolean isInitial() { + return getParents().isEmpty(); + } + + public void setModifiedFiles(@NotNull final List<FileStatus> files) { + myModifiedFiles = files; + } + + @NotNull + public List<FileStatus> getModifiedFiles() { + return myModifiedFiles; + } + + @NotNull + public String getBranch() { + return myBranch; + } + + public void setBranch(@Nullable String branch) { + if (branch == null || branch.trim().isEmpty() || DEFAULT_BRANCH_NAME.equals(branch)) branch = DEFAULT_BRANCH_NAME; + myBranch = branch; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSetRevision.java Fri Sep 24 19:45:30 2010 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSetRevision.java Thu Aug 06 12:15:36 2020 +0300 @@ -1,99 +1,99 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import org.jetbrains.annotations.NotNull; - -/** - * @author Pavel.Sher - */ -public class ChangeSetRevision { - private final int myRevNumber; - @NotNull - private final String myId; - - public ChangeSetRevision(final int revNumber, @NotNull final String id) { - myRevNumber = revNumber; - myId = id; - } - - /** - * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) - * @param fullVersion full changeset version as reported by hg log command - */ - public ChangeSetRevision(@NotNull final String fullVersion) { - try { - int colon = fullVersion.indexOf(":"); - if (colon != -1) { - myRevNumber = Integer.parseInt(fullVersion.substring(0, colon)); - myId = fullVersion.substring(colon+1); - } else { - myRevNumber = -1; - myId = fullVersion; - } - } catch (Throwable e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Returns changeset revision id - * @return changeset revision id - */ - @NotNull - public String getId() { - return myId; - } - - /** - * Returns changeset revision number - * @return changeset revision number - */ - public int getRevNumber() { - return myRevNumber; - } - - /** - * Returns full changeset version as reported by hg log command: revnum:revid - * @return full changeset version as reported by hg log - */ - @NotNull - public String getFullVersion() { - return myRevNumber + ":" + myId; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final ChangeSetRevision that = (ChangeSetRevision) o; - - return myRevNumber == that.myRevNumber && myId.equals(that.myId); - } - - @Override - public int hashCode() { - int result = myRevNumber; - result = 31 * result + myId.hashCode(); - return result; - } - - @Override - public String toString() { - return "change:" + myId; - } -} +/* + * Copyright 2000-2018 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Pavel.Sher + */ +public class ChangeSetRevision { + private final int myRevNumber; + @NotNull + private final String myId; + + public ChangeSetRevision(final int revNumber, @NotNull final String id) { + myRevNumber = revNumber; + myId = id; + } + + /** + * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) + * @param fullVersion full changeset version as reported by hg log command + */ + public ChangeSetRevision(@NotNull final String fullVersion) { + try { + int colon = fullVersion.indexOf(":"); + if (colon != -1) { + myRevNumber = Integer.parseInt(fullVersion.substring(0, colon)); + myId = fullVersion.substring(colon+1); + } else { + myRevNumber = -1; + myId = fullVersion; + } + } catch (Throwable e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Returns changeset revision id + * @return changeset revision id + */ + @NotNull + public String getId() { + return myId; + } + + /** + * Returns changeset revision number + * @return changeset revision number + */ + public int getRevNumber() { + return myRevNumber; + } + + /** + * Returns full changeset version as reported by hg log command: revnum:revid + * @return full changeset version as reported by hg log + */ + @NotNull + public String getFullVersion() { + return myRevNumber + ":" + myId; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ChangeSetRevision that = (ChangeSetRevision) o; + + return myRevNumber == that.myRevNumber && myId.equals(that.myId); + } + + @Override + public int hashCode() { + int result = myRevNumber; + result = 31 * result + myId.hashCode(); + return result; + } + + @Override + public String toString() { + return "change:" + myId; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangedFilesCommand.java Fri Sep 24 19:45:30 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * @author Pavel.Sher - */ -public class ChangedFilesCommand extends BaseCommand { - private String myRevId; - - public ChangedFilesCommand(@NotNull final Settings settings) { - super(settings); - } - - public void setRevId(@NotNull final String revId) { - myRevId = revId; - } - - public List<ModifiedFile> execute() throws VcsException { - File styleFile; - try { - styleFile = getStyleFile(); - } catch (IOException e) { - throw new VcsException("Unable to create style file: " + e.toString(), e); - } - try { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("log"); - cli.addParameter("-r");