| author | paulson | 
| Mon, 08 Nov 2021 09:31:26 +0000 | |
| changeset 74730 | 25f5f1fa31bb | 
| parent 73702 | 7202e12cb324 | 
| child 75393 | 87ebf5a50283 | 
| permissions | -rw-r--r-- | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 1 | /* Title: Pure/General/mercurial.scala | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 3 | |
| 64280 | 4 | Support for Mercurial repositories, with local or remote repository clone | 
| 5 | and working directory (via ssh connection). | |
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 6 | */ | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 7 | |
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 8 | package isabelle | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 9 | |
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 10 | |
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 11 | import scala.annotation.tailrec | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 12 | import scala.collection.mutable | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 13 | |
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 14 | |
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 15 | object Mercurial | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 16 | {
 | 
| 66895 | 17 | type Graph = isabelle.Graph[String, Unit] | 
| 18 | ||
| 19 | ||
| 73611 | 20 | /* HTTP server */ | 
| 21 | ||
| 22 | object Server | |
| 23 |   {
 | |
| 24 | def apply(root: String): Server = new Server(root) | |
| 25 | ||
| 26 | def start(root: Path): Server = | |
| 27 |     {
 | |
| 28 | val hg = repository(root) | |
| 73609 | 29 | |
| 73611 | 30 | val server_process = Future.promise[Bash.Process] | 
| 31 | val server_root = Future.promise[String] | |
| 32 |       Isabelle_Thread.fork("hg") {
 | |
| 33 | val process = | |
| 34 |           Exn.capture { Bash.process(hg.command_line("serve", options = "--port 0 --print-url")) }
 | |
| 35 | server_process.fulfill_result(process) | |
| 36 | Exn.release(process).result(progress_stdout = | |
| 37 |           line => if (!server_root.is_finished) {
 | |
| 38 |             server_root.fulfill(Library.try_unsuffix("/", line).getOrElse(line))
 | |
| 39 | }) | |
| 40 | } | |
| 41 | server_process.join | |
| 42 | ||
| 43 |       new Server(server_root.join) {
 | |
| 44 | override def close(): Unit = server_process.join.terminate() | |
| 45 | } | |
| 46 | } | |
| 73609 | 47 | } | 
| 48 | ||
| 73611 | 49 | class Server private(val root: String) extends AutoCloseable | 
| 73609 | 50 |   {
 | 
| 51 | override def toString: String = root | |
| 52 | ||
| 73611 | 53 | def close(): Unit = () | 
| 54 | ||
| 73610 | 55 | def changeset(rev: String = "tip", raw: Boolean = false): String = | 
| 56 | root + (if (raw) "/raw-rev/" else "/rev/") + rev | |
| 57 | ||
| 58 | def file(path: Path, rev: String = "tip", raw: Boolean = false): String = | |
| 59 | root + (if (raw) "/raw-file/" else "/file/") + rev + "/" + path.expand.implode | |
| 60 | ||
| 61 | def archive(rev: String = "tip"): String = | |
| 62 | root + "/archive/" + rev + ".tar.gz" | |
| 63 | ||
| 64 | def read_changeset(rev: String = "tip"): String = | |
| 65 | Url.read(changeset(rev = rev, raw = true)) | |
| 66 | ||
| 67 | def read_file(path: Path, rev: String = "tip"): String = | |
| 68 | Url.read(file(path, rev = rev, raw = true)) | |
| 69 | ||
| 70 | def download_archive(rev: String = "tip", progress: Progress = new Progress): HTTP.Content = | |
| 71 | Isabelle_System.download(archive(rev = rev), progress = progress) | |
| 72 | ||
| 73 | def download_dir(dir: Path, rev: String = "tip", progress: Progress = new Progress): Unit = | |
| 74 |     {
 | |
| 75 | Isabelle_System.new_directory(dir) | |
| 76 |       Isabelle_System.with_tmp_file("rev", ext = ".tar.gz")(archive_path =>
 | |
| 77 |       {
 | |
| 78 | val content = download_archive(rev = rev, progress = progress) | |
| 79 | Bytes.write(archive_path, content.bytes) | |
| 80 |         progress.echo("Unpacking " + rev + ".tar.gz")
 | |
| 73624 | 81 |         Isabelle_System.gnutar("-xzf " + File.bash_path(archive_path),
 | 
| 82 | dir = dir, original_owner = true, strip = 1).check | |
| 73610 | 83 | }) | 
| 84 | } | |
| 73609 | 85 | } | 
| 86 | ||
| 87 | ||
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 88 | /* command-line syntax */ | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 89 | |
| 63999 | 90 | def optional(s: String, prefix: String = ""): String = | 
| 64304 | 91 | if (s == "") "" else " " + prefix + " " + Bash.string(s) | 
| 63999 | 92 | |
| 93 | def opt_flag(flag: String, b: Boolean): String = if (b) " " + flag else "" | |
| 94 | def opt_rev(s: String): String = optional(s, "--rev") | |
| 95 | def opt_template(s: String): String = optional(s, "--template") | |
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 96 | |
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 97 | |
| 73520 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 98 | /* repository archives */ | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 99 | |
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 100 |   private val Archive_Node = """^node: (\S{12}).*$""".r
 | 
| 73521 | 101 | private val Archive_Tag = """^tag: (\S+).*$""".r | 
| 73520 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 102 | |
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 103 | sealed case class Archive_Info(lines: List[String]) | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 104 |   {
 | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 105 |     def id: Option[String] = lines.collectFirst({ case Archive_Node(a) => a })
 | 
| 73521 | 106 | def tags: List[String] = for (Archive_Tag(tag) <- lines if tag != "tip") yield tag | 
| 73520 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 107 | } | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 108 | |
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 109 | def archive_info(root: Path): Option[Archive_Info] = | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 110 |   {
 | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 111 |     val path = root + Path.explode(".hg_archival.txt")
 | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 112 | if (path.is_file) Some(Archive_Info(Library.trim_split_lines(File.read(path)))) else None | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 113 | } | 
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 114 | |
| 73521 | 115 | def archive_id(root: Path): Option[String] = | 
| 116 | archive_info(root).flatMap(_.id) | |
| 117 | ||
| 118 | def archive_tags(root: Path): Option[String] = | |
| 119 |     archive_info(root).map(info => info.tags.mkString(" "))
 | |
| 73520 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 120 | |
| 
4cba4e250c28
clarified ISABELLE_ID: distribution vs. hg archive vs. hg repos;
 wenzelm parents: 
73483diff
changeset | 121 | |
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 122 | /* repository access */ | 
| 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 123 | |
| 66570 | 124 | def is_repository(root: Path, ssh: SSH.System = SSH.Local): Boolean = | 
| 125 |     ssh.is_dir(root + Path.explode(".hg")) &&
 | |
| 126 |     new Repository(root, ssh).command("root").ok
 | |
| 64330 | 127 | |
| 66570 | 128 | def repository(root: Path, ssh: SSH.System = SSH.Local): Repository = | 
| 64168 | 129 |   {
 | 
| 130 | val hg = new Repository(root, ssh) | |
| 131 |     hg.command("root").check
 | |
| 132 | hg | |
| 133 | } | |
| 134 | ||
| 66570 | 135 | def find_repository(start: Path, ssh: SSH.System = SSH.Local): Option[Repository] = | 
| 65559 | 136 |   {
 | 
| 71601 | 137 | @tailrec def find(root: Path): Option[Repository] = | 
| 65559 | 138 | if (is_repository(root, ssh)) Some(repository(root, ssh = ssh)) | 
| 139 | else if (root.is_root) None | |
| 140 | else find(root + Path.parent) | |
| 141 | ||
| 66570 | 142 | find(ssh.expand_path(start)) | 
| 65559 | 143 | } | 
| 144 | ||
| 67066 | 145 | private def make_repository(root: Path, cmd: String, args: String, ssh: SSH.System = SSH.Local) | 
| 146 | : Repository = | |
| 64168 | 147 |   {
 | 
| 64230 | 148 | val hg = new Repository(root, ssh) | 
| 72375 | 149 | ssh.make_directory(hg.root.dir) | 
| 67066 | 150 | hg.command(cmd, args, repository = false).check | 
| 64168 | 151 | hg | 
| 152 | } | |
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 153 | |
| 67065 | 154 | def init_repository(root: Path, ssh: SSH.System = SSH.Local): Repository = | 
| 67066 | 155 | make_repository(root, "init", ssh.bash_path(root), ssh = ssh) | 
| 67065 | 156 | |
| 157 | def clone_repository(source: String, root: Path, | |
| 158 | rev: String = "", options: String = "", ssh: SSH.System = SSH.Local): Repository = | |
| 159 | make_repository(root, "clone", | |
| 67066 | 160 | options + " " + Bash.string(source) + " " + ssh.bash_path(root) + opt_rev(rev), ssh = ssh) | 
| 67065 | 161 | |
| 73611 | 162 | def setup_repository(source: String, root: Path, ssh: SSH.System = SSH.Local): Repository = | 
| 64252 
e84cba30d7ff
clarified setup_repository: more uniform pull vs. clone, without update;
 wenzelm parents: 
64233diff
changeset | 163 |   {
 | 
| 66570 | 164 |     if (ssh.is_dir(root)) { val hg = repository(root, ssh = ssh); hg.pull(remote = source); hg }
 | 
| 66105 
8889aad1ff92
reverted 94cad7590015: does not help much on Windows;
 wenzelm parents: 
66104diff
changeset | 165 | else clone_repository(source, root, options = "--noupdate", ssh = ssh) | 
| 64252 
e84cba30d7ff
clarified setup_repository: more uniform pull vs. clone, without update;
 wenzelm parents: 
64233diff
changeset | 166 | } | 
| 64230 | 167 | |
| 66570 | 168 | class Repository private[Mercurial](root_path: Path, ssh: SSH.System = SSH.Local) | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 169 |   {
 | 
| 64167 
097d122222f6
support remote repositories via ssh command execution;
 wenzelm parents: 
64162diff
changeset | 170 | hg => | 
| 
097d122222f6
support remote repositories via ssh command execution;
 wenzelm parents: 
64162diff
changeset | 171 | |
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 172 | val root: Path = ssh.expand_path(root_path) | 
| 66570 | 173 | def root_url: String = ssh.hg_url + root.implode | 
| 64230 | 174 | |
| 71562 | 175 | override def toString: String = ssh.hg_url + root.implode | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 176 | |
| 73611 | 177 | def command_line(name: String, args: String = "", options: String = "", | 
| 178 | repository: Boolean = true): String = | |
| 64167 
097d122222f6
support remote repositories via ssh command execution;
 wenzelm parents: 
64162diff
changeset | 179 |     {
 | 
| 73611 | 180 |       "export LANG=C HGPLAIN=\n\"${HG:-hg}\" --config " + Bash.string("defaults." + name + "=") +
 | 
| 181 | (if (repository) " --repository " + ssh.bash_path(root) else "") + | |
| 182 | " --noninteractive " + name + " " + options + " " + args | |
| 183 | } | |
| 184 | ||
| 185 | def command( | |
| 186 | name: String, args: String = "", options: String = "", | |
| 187 | repository: Boolean = true): Process_Result = | |
| 188 |     {
 | |
| 189 | ssh.execute(command_line(name, args = args, options = options, repository = repository)) | |
| 64167 
097d122222f6
support remote repositories via ssh command execution;
 wenzelm parents: 
64162diff
changeset | 190 | } | 
| 63999 | 191 | |
| 67068 | 192 | def add(files: List[Path]): Unit = | 
| 71601 | 193 |       hg.command("add", files.map(ssh.bash_path).mkString(" "))
 | 
| 67068 | 194 | |
| 64505 | 195 | def archive(target: String, rev: String = "", options: String = ""): Unit = | 
| 196 |       hg.command("archive", opt_rev(rev) + " " + Bash.string(target), options).check
 | |
| 197 | ||
| 63999 | 198 |     def heads(template: String = "{node|short}\n", options: String = ""): List[String] =
 | 
| 64168 | 199 |       hg.command("heads", opt_template(template), options).check.out_lines
 | 
| 63999 | 200 | |
| 64232 
367d83d6030e
clarified hg.id operation, with explicit tip as default;
 wenzelm parents: 
64230diff
changeset | 201 | def identify(rev: String = "tip", options: String = ""): String = | 
| 64168 | 202 |       hg.command("id", opt_rev(rev), options).check.out_lines.headOption getOrElse ""
 | 
| 63998 | 203 | |
| 64232 
367d83d6030e
clarified hg.id operation, with explicit tip as default;
 wenzelm parents: 
64230diff
changeset | 204 | def id(rev: String = "tip"): String = identify(rev, options = "-i") | 
| 
367d83d6030e
clarified hg.id operation, with explicit tip as default;
 wenzelm parents: 
64230diff
changeset | 205 | |
| 73524 | 206 | def tags(rev: String = "tip"): String = | 
| 207 |     {
 | |
| 208 | val result = identify(rev, options = "-t") | |
| 209 |       Library.space_explode(' ', result).filterNot(_ == "tip").mkString(" ")
 | |
| 210 | } | |
| 73521 | 211 | |
| 71313 | 212 | def paths(args: String = "", options: String = ""): List[String] = | 
| 213 |       hg.command("paths", args = args, options = options).check.out_lines
 | |
| 214 | ||
| 63998 | 215 | def manifest(rev: String = "", options: String = ""): List[String] = | 
| 64168 | 216 |       hg.command("manifest", opt_rev(rev), options).check.out_lines
 | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 217 | |
| 64033 | 218 | def log(rev: String = "", template: String = "", options: String = ""): String = | 
| 64168 | 219 |       hg.command("log", opt_rev(rev) + opt_template(template), options).check.out
 | 
| 64027 | 220 | |
| 67755 | 221 |     def parent(): String = log(rev = "p1()", template = "{node|short}")
 | 
| 222 | ||
| 73340 | 223 | def push( | 
| 224 | remote: String = "", rev: String = "", force: Boolean = false, options: String = ""): Unit = | |
| 64348 
4c253e84ae62
clarified push/pull chain: current ISABELLE_HOME may server as source for changes that are not published on isabelle_repos_source yet (e.g. isabelle-release branch);
 wenzelm parents: 
64347diff
changeset | 225 |     {
 | 
| 
4c253e84ae62
clarified push/pull chain: current ISABELLE_HOME may server as source for changes that are not published on isabelle_repos_source yet (e.g. isabelle-release branch);
 wenzelm parents: 
64347diff
changeset | 226 |       hg.command("push", opt_rev(rev) + opt_flag("--force", force) + optional(remote), options).
 | 
| 64408 
50bcf976f276
clarified hg push return code: 1 means "nothing to push";
 wenzelm parents: 
64348diff
changeset | 227 | check_rc(rc => rc == 0 | rc == 1) | 
| 64348 
4c253e84ae62
clarified push/pull chain: current ISABELLE_HOME may server as source for changes that are not published on isabelle_repos_source yet (e.g. isabelle-release branch);
 wenzelm parents: 
64347diff
changeset | 228 | } | 
| 
4c253e84ae62
clarified push/pull chain: current ISABELLE_HOME may server as source for changes that are not published on isabelle_repos_source yet (e.g. isabelle-release branch);
 wenzelm parents: 
64347diff
changeset | 229 | |
| 63999 | 230 | def pull(remote: String = "", rev: String = "", options: String = ""): Unit = | 
| 64168 | 231 |       hg.command("pull", opt_rev(rev) + optional(remote), options).check
 | 
| 63999 | 232 | |
| 64168 | 233 | def update( | 
| 73340 | 234 | rev: String = "", clean: Boolean = false, check: Boolean = false, options: String = ""): Unit = | 
| 63999 | 235 |     {
 | 
| 64168 | 236 |       hg.command("update",
 | 
| 237 |         opt_rev(rev) + opt_flag("--clean", clean) + opt_flag("--check", check), options).check
 | |
| 63999 | 238 | } | 
| 65819 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 239 | |
| 65822 
17b8528c2f53
clarified notion of known files (before actual commit);
 wenzelm parents: 
65819diff
changeset | 240 | def known_files(): List[String] = | 
| 65825 
11f87ab51ddb
more robust command invocation, without defaults from hgrc;
 wenzelm parents: 
65822diff
changeset | 241 |       hg.command("status", options = "--modified --added --clean --no-status").check.out_lines
 | 
| 65819 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 242 | |
| 66895 | 243 | def graph(): Graph = | 
| 65819 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 244 |     {
 | 
| 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 245 |       val Node = """^node: (\w{12}) (\w{12}) (\w{12})""".r
 | 
| 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 246 | val log_result = | 
| 65825 
11f87ab51ddb
more robust command invocation, without defaults from hgrc;
 wenzelm parents: 
65822diff
changeset | 247 |         log(template = """node: {node|short} {p1node|short} {p2node|short}\n""")
 | 
| 73359 | 248 |       split_lines(log_result).foldLeft(Graph.string[Unit]) {
 | 
| 65819 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 249 | case (graph, Node(x, y, z)) => | 
| 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 250 | val deps = List(y, z).filterNot(s => s.forall(_ == '0')) | 
| 73359 | 251 | val graph1 = (x :: deps).foldLeft(graph)(_.default_node(_, ())) | 
| 252 |           deps.foldLeft(graph1)({ case (g, dep) => g.add_edge(dep, x) })
 | |
| 65819 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 253 | case (graph, _) => graph | 
| 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 254 | } | 
| 
ff3dc9325eaa
explore repository structure, with minimal assumptions about "hg log" output;
 wenzelm parents: 
65818diff
changeset | 255 | } | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 256 | } | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 257 | |
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 258 | |
| 67782 
7e223a05e6d8
clarified notion of unknown files: ignore files outside of a Mercurial repository;
 wenzelm parents: 
67755diff
changeset | 259 | /* check files */ | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 260 | |
| 67782 
7e223a05e6d8
clarified notion of unknown files: ignore files outside of a Mercurial repository;
 wenzelm parents: 
67755diff
changeset | 261 | def check_files(files: List[Path], ssh: SSH.System = SSH.Local): (List[Path], List[Path]) = | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 262 |   {
 | 
| 67782 
7e223a05e6d8
clarified notion of unknown files: ignore files outside of a Mercurial repository;
 wenzelm parents: 
67755diff
changeset | 263 | val outside = new mutable.ListBuffer[Path] | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 264 | val unknown = new mutable.ListBuffer[Path] | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 265 | |
| 73340 | 266 | @tailrec def check(paths: List[Path]): Unit = | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 267 |     {
 | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 268 |       paths match {
 | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 269 | case path :: rest => | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 270 |           find_repository(path, ssh) match {
 | 
| 67782 
7e223a05e6d8
clarified notion of unknown files: ignore files outside of a Mercurial repository;
 wenzelm parents: 
67755diff
changeset | 271 | case None => outside += path; check(rest) | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 272 | case Some(hg) => | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 273 | val known = | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 274 | hg.known_files().iterator.map(name => | 
| 65833 | 275 | (hg.root + Path.explode(name)).canonical_file).toSet | 
| 276 | if (!known(path.canonical_file)) unknown += path | |
| 277 | check(rest.filterNot(p => known(p.canonical_file))) | |
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 278 | } | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 279 | case Nil => | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 280 | } | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 281 | } | 
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 282 | |
| 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 283 | check(files) | 
| 67782 
7e223a05e6d8
clarified notion of unknown files: ignore files outside of a Mercurial repository;
 wenzelm parents: 
67755diff
changeset | 284 | (outside.toList, unknown.toList) | 
| 65832 
2fb85623c386
implicitly check for unknown files (not part of a Mercurial repository);
 wenzelm parents: 
65825diff
changeset | 285 | } | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 286 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 287 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 288 | /* setup remote vs. local repository */ | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 289 | |
| 73340 | 290 | private def edit_hgrc(local_hg: Repository, path_name: String, source: String): Unit = | 
| 71313 | 291 |   {
 | 
| 292 |     val hgrc = local_hg.root + Path.explode(".hg/hgrc")
 | |
| 293 |     def header(line: String): Boolean = line.startsWith("[paths]")
 | |
| 294 | val Entry = """^(\S+)\s*=\s*(.*)$""".r | |
| 295 | val new_entry = path_name + " = " + source | |
| 296 | ||
| 297 | def commit(lines: List[String]): Boolean = | |
| 298 |     {
 | |
| 71320 | 299 | File.write(hgrc, cat_lines(lines)) | 
| 71313 | 300 | true | 
| 301 | } | |
| 302 | val edited = | |
| 303 |       hgrc.is_file && {
 | |
| 304 | val lines = split_lines(File.read(hgrc)) | |
| 71383 | 305 |         lines.count(header) == 1 && {
 | 
| 71313 | 306 |           if (local_hg.paths(options = "-q").contains(path_name)) {
 | 
| 307 | val old_source = local_hg.paths(args = path_name).head | |
| 71320 | 308 | val old_entry = path_name + ".old = " + old_source | 
| 71313 | 309 | val lines1 = | 
| 310 |               lines.map {
 | |
| 71320 | 311 | case Entry(a, b) if a == path_name && b == old_source => | 
| 312 | new_entry + "\n" + old_entry | |
| 71313 | 313 | case line => line | 
| 314 | } | |
| 315 | lines != lines1 && commit(lines1) | |
| 316 | } | |
| 317 |           else {
 | |
| 318 | val prefix = lines.takeWhile(line => !header(line)) | |
| 319 | val n = prefix.length | |
| 320 | commit(prefix ::: List(lines(n), new_entry) ::: lines.drop(n + 1)) | |
| 321 | } | |
| 322 | } | |
| 323 | } | |
| 324 | if (!edited) File.append(hgrc, "\n[paths]\n" + new_entry + "\n") | |
| 325 | } | |
| 326 | ||
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 327 | val default_path_name = "default" | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 328 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 329 | def hg_setup( | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 330 | remote: String, | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 331 | local_path: Path, | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 332 | remote_name: String = "", | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 333 | path_name: String = default_path_name, | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 334 | remote_exists: Boolean = false, | 
| 73340 | 335 | progress: Progress = new Progress): Unit = | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 336 |   {
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 337 | /* local repository */ | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 338 | |
| 72375 | 339 | Isabelle_System.make_directory(local_path) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 340 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 341 | val repos_name = | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 342 | proper_string(remote_name) getOrElse local_path.absolute.base.implode | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 343 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 344 | val local_hg = | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 345 | if (is_repository(local_path)) repository(local_path) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 346 | else init_repository(local_path) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 347 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 348 |     progress.echo("Local repository " + local_hg.root.absolute)
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 349 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 350 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 351 | /* remote repository */ | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 352 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 353 | val remote_url = | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 354 |       remote match {
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 355 |         case _ if remote.startsWith("ssh://") =>
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 356 | val ssh_url = remote + "/" + repos_name | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 357 | |
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 358 |           if (!remote_exists) {
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 359 |             try { local_hg.command("init", ssh_url, repository = false).check }
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 360 |             catch { case ERROR(msg) => progress.echo_warning(msg) }
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 361 | } | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 362 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 363 | ssh_url | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 364 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 365 | case SSH.Target(user, host) => | 
| 71314 | 366 | val phabricator = Phabricator.API(user, host) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 367 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 368 | var repos = | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 369 |             phabricator.get_repositories().find(r => r.short_name == repos_name) getOrElse {
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 370 |               if (remote_exists) {
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 371 |                 error("Remote repository " +
 | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 372 | quote(phabricator.hg_url + "/source/" + repos_name) + " expected to exist") | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 373 | } | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 374 | else phabricator.create_repository(repos_name, short_name = repos_name) | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 375 | } | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 376 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 377 |           while (repos.importing) {
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 378 |             progress.echo("Awaiting remote repository ...")
 | 
| 73702 
7202e12cb324
tuned signature --- following hints by IntelliJ IDEA;
 wenzelm parents: 
73624diff
changeset | 379 | Time.seconds(0.5).sleep() | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 380 | repos = phabricator.the_repository(repos.phid) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 381 | } | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 382 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 383 | repos.ssh_url | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 384 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 385 |         case _ => error("Malformed remote specification " + quote(remote))
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 386 | } | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 387 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 388 |     progress.echo("Remote repository " + quote(remote_url))
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 389 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 390 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 391 | /* synchronize local and remote state */ | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 392 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 393 |     progress.echo("Synchronizing ...")
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 394 | |
| 71313 | 395 | edit_hgrc(local_hg, path_name, remote_url) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 396 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 397 | local_hg.pull(options = "-u") | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 398 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 399 | local_hg.push(remote = remote_url) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 400 | } | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 401 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 402 | val isabelle_tool = | 
| 72763 | 403 |     Isabelle_Tool("hg_setup", "setup remote vs. local Mercurial repository",
 | 
| 404 | Scala_Project.here, args => | |
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 405 |     {
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 406 | var remote_name = "" | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 407 | var path_name = default_path_name | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 408 | var remote_exists = false | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 409 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 410 |       val getopts = Getopts("""
 | 
| 71322 | 411 | Usage: isabelle hg_setup [OPTIONS] REMOTE LOCAL_DIR | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 412 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 413 | Options are: | 
| 71322 | 414 | -n NAME remote repository name (default: base name of LOCAL_DIR) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 415 | -p PATH Mercurial path name (default: """ + quote(default_path_name) + """) | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 416 | -r assume that remote repository already exists | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 417 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 418 | Setup a remote vs. local Mercurial repository: REMOTE either refers to a | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 419 | Phabricator server "user@host" or SSH file server "ssh://user@host/path". | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 420 | """, | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 421 | "n:" -> (arg => remote_name = arg), | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 422 | "p:" -> (arg => path_name = arg), | 
| 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 423 | "r" -> (_ => remote_exists = true)) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 424 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 425 | val more_args = getopts(args) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 426 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 427 | val (remote, local_path) = | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 428 |         more_args match {
 | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 429 | case List(arg1, arg2) => (arg1, Path.explode(arg2)) | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 430 | case _ => getopts.usage() | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 431 | } | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 432 | |
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 433 | val progress = new Console_Progress | 
| 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 434 | |
| 71319 
26614beb3529
removed somewhat pointless option -R: more careful inspection of hgrc is required in practice;
 wenzelm parents: 
71315diff
changeset | 435 | hg_setup(remote, local_path, remote_name = remote_name, path_name = path_name, | 
| 71321 
edf3210a61a2
added option -r: support more robust consolidation of local clones with varying names;
 wenzelm parents: 
71320diff
changeset | 436 | remote_exists = remote_exists, progress = progress) | 
| 71312 
937328d61436
added command hg_setup: setup remote vs. local Mercurial repository;
 wenzelm parents: 
68566diff
changeset | 437 | }) | 
| 63997 
e11ccb5aa82f
more formal Mercurial support (with the potential to upgrade to command server);
 wenzelm parents: diff
changeset | 438 | } |