ラベル Mercurial の投稿を表示しています。 すべての投稿を表示
ラベル Mercurial の投稿を表示しています。 すべての投稿を表示

2020年7月20日月曜日

Debian SidのMercurialがPython 3へ移行したためinfo.pyに異常が出た (workaroundあり)

Debian SidのMercurialが5.4.1→5.4.2にupgradeされた。このversionでは(Mercurialが依存する) Pythonが2.7→3へ変更された。

この影響で、Mercurialのextensionとして導入しているinfo.pyの実行に不具合が発生した:

> % hg st .
> *** failed to import extension info from ~/.hg.d/info.py: unicode 'info' found in cmdtable
> *** (use b'' to make it byte string)
> ...

info.pyを読み込む際にerrorが発生してimportに失敗している。`bytes`を想定している`cmdtable`内にUnicodeとして認識されたstringが混入したため。

Workaroundとして、「`b''`を使って (explicit type conversionして)ね!」というerror messageに従い、info.pyにて:

> - @command('info')
> + @command(b'info')

の変更を行い解決した。


Python 3.xでのstrとbytesについて


Python 3では`str`がUnicodeへ変更された (Unicodeが`str`になった)一方で、Mercurial (のAPI)は`bytes`を想定している。Python 3は (Python 2 seriesのような)`str` (Unicode)と`bytes`のimplicit type conversionを行わないので、このような事例はerrorとして検出される。

以下、Python 3.8.4のdocumentationより引用:

Note
 
For Python 2.x users: In the Python 2.x series, a variety of implicit conversions between 8-bit strings (the closest thing 2.x offers to a built-in binary data type) and Unicode strings were permitted. This was a backwards compatibility workaround to account for the fact that Python originally only supported 8-bit text, and Unicode text was a later addition. In Python 3.x, those implicit conversions are gone - conversions between 8-bit binary data and Unicode text must be explicit, and bytes and string objects will always compare unequal.

cf. [Built-in Types — Python 3.8.4 documentation](https://docs.python.org/3/library/stdtypes.html#bytes)

(要約)

Python 2.xまでは色々な過去の経緯もあってUnicode文字列と8bit文字列の暗黙的な変換が横行していた。Python 3.xからは一切暗黙的に変換しないのでプログラマは明示的に変換する必要がある。`str`と`bytes`の比較は常に等しくない。


2018年7月16日月曜日

repositoryのprotocol指定が間違っているとhg pullが失敗する

当たり前と言えば当たり前のtitleなのだが。これまでhttpでokだった場合でも、httpsへの移行が進んでいるのだなと。


Mozilla FirefoxなどのsoftwareはMercurialで管理されている。

Firefoxの最新版 (mozilla-central)を取得しようとした所、失敗した:

% hg pull -u
pulling from http://hg.mozilla.org/mozilla-central/
abort: error: Connection reset by peer

もしかしたらrepositoryの場所が移動したり、serverが死んだりしているのかと確認してみたが、普通に生きている。


ふと、protocolがhttpでなくhttpsであると気付きこれを修正してみた。

% vim .hg/hgrc
# example repository config (see 'hg help config' for more info)
[paths]
default = https://hg.mozilla.org/mozilla-central/

正常にpullできるようになった。


2018年5月26日土曜日

hg infoをMercurial 4.6に対応させる

Mercurial 4.6に更新されたために色々な部分が変更された (cf. [WhatsNew - Mercurial](https://www.mercurial-scm.org/wiki/WhatsNew))。

現在のMercurial repositoryに関する情報を表示するhg info (cf. [InfoExtension - Mercurial](https://www.mercurial-scm.org/wiki/InfoExtension))というextensionを導入しているのだが、4.6へのupgradeに伴ってerrorを吐くようになったので修正。

原因は2つある:

1. cmdutil.commandが削除された
2. changectx()の仕様変更

cmdutilの仕様変更への対処


changeset:   37957:fb0de0bcd297
user:        Matt Harbison <matt_harbison@yahoo.com>
date:        Thu May 10 21:53:48 2018 -0400
summary:     cmdutil: drop deprecated precursor of registrar.command (API)
diff -r f1f8b655da32 -r fb0de0bcd297 mercurial/cmdutil.py
--- a/mercurial/cmdutil.py      Fri May 11 00:53:29 2018 -0400
+++ b/mercurial/cmdutil.py      Thu May 10 21:53:48 2018 -0400
@@ -37,7 +37,6 @@
     patch,
     pathutil,
     pycompat,
-    registrar,
     revlog,
     rewriteutil,
     scmutil,
@@ -3151,12 +3150,6 @@
         if f in copied:
             repo.dirstate.copy(copied[f], f)

-class command(registrar.command):
-    """deprecated: used registrar.command instead"""
-    def _doregister(self, func, name, *args, **kwargs):
-        func._deprecatedregistrar = True  # flag for deprecwarn in extensions.p
y
-        return super(command, self)._doregister(func, name, *args, **kwargs)
-
 # a list of (ui, repo, otherpeer, opts, missing) functions called by
 # commands.outgoing.  "missing" is "missing" of the result of
 # "findcommonoutgoing()"
diff -r f1f8b655da32 -r fb0de0bcd297 mercurial/extensions.py
--- a/mercurial/extensions.py   Fri May 11 00:53:29 2018 -0400
+++ b/mercurial/extensions.py   Thu May 10 21:53:48 2018 -0400
@@ -145,9 +145,6 @@
     """Check if extension commands have required attributes"""
     for c, e in cmdtable.iteritems():
         f = e[0]
-        if getattr(f, '_deprecatedregistrar', False):
-            ui.deprecwarn("cmdutil.command is deprecated, use "
-                          "registrar.command to register '%s'" % c, '4.6')
         missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
         if not missing:
             continue
diff -r f1f8b655da32 -r fb0de0bcd297 tests/test-extension.t
--- a/tests/test-extension.t    Fri May 11 00:53:29 2018 -0400
+++ b/tests/test-extension.t    Thu May 10 21:53:48 2018 -0400
@@ -1697,10 +1697,6 @@
   >     pass
   > EOF

-  $ hg --config extensions.nonregistrar=`pwd`/nonregistrar.py version > /dev/nu
ll
-  devel-warn: cmdutil.command is deprecated, use registrar.command to register
'foo'
-  (compatibility will be dropped after Mercurial-4.6, update your code.) * (glo
b)
-
 Prohibit the use of unicode strings as the default value of options

   $ hg init $TESTTMP/opt-unicode-default

代わりにregistrar.commandを使えとあるので書き換えた。

- from mercurial import cmdutil
+ from mercurial import registrar

- command = cmdutil.command(cmdtable)
+ command = registrar.command(cmdtable)

changectx()の仕様変更への対処


changeset:   37852:8b86acc7aa64
user:        Martin von Zweigbergk <martinvonz@google.com>
date:        Sat Apr 28 23:16:41 2018 -0700
summary:     context: drop support for looking up context by ambiguous changeid
(API)
... 
-def changectxdeprecwarn(repo):
-    # changectx's constructor will soon lose support for these forms of
-    # changeids:
-    #  * stringinfied ints
-    #  * bookmarks, tags, branches, and other namespace identifiers
-    #  * hex nodeid prefixes
-    #
-    # Depending on your use case, replace repo[x] by one of these:
-    #  * If you want to support general revsets, use scmutil.revsingle(x)
-    #  * If you know that "x" is a stringified int, use repo[int(x)]
-    #  * If you know that "x" is a bookmark, use repo._bookmarks.changectx(x)
-    #  * If you know that "x" is a tag, use repo[repo.tags()[x]]
-    #  * If you know that "x" is a branch or in some other namespace,
-    #    use the appropriate mechanism for that namespace
-    #  * If you know that "x" is a hex nodeid prefix, use
-    #    repo[scmutil.resolvehexnodeidprefix(repo, x)]
-    #  * If "x" is a string that can be any of the above, but you don't want
-    #    to allow general revsets (perhaps because "x" may come from a remote
-    #    user and the revset may be too costly), use scmutil.revsymbol(repo, x)
-    #  * If "x" can be a mix of the above, you'll have to figure it out
-    #    yourself
-    repo.ui.deprecwarn("changectx.__init__ is getting more limited, see "
-                       "context.changectxdeprecwarn() for details", "4.6",
-                       stacklevel=4)

それぞれ以下のように対応した:

-    ui.write(_("Base Hash: %s [hg id -r0]\n") % (hex(repo.changectx(0).node()),))
+    ui.write(_("Base Hash: %s [hg id -r0]\n") % (hex(repo.changelog.node(0)),))

changectx().node()が削除されたので、changelog.node()に変更。

-    ui.write(_("Files: %s [hg manifest | wc -l]\n") % (len(repo.changectx(numrev-1).manifest()),))
+    ui.write(_("Files: %s [hg manifest | wc -l]\n") % (len(repo[numrev-1].manifest()),))

changectx().manifest()が削除されたので、repo[].manifest()に変更。


まとめ


--- info.py.orig 2018-05-26 15:23:14.524041991 +0900
+++ info.py 2018-05-26 15:23:25.523203385 +0900
@@ -7,9 +7,15 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.

+from mercurial import registrar
 from mercurial.i18n import _
 from mercurial.node import short, hex

+cmdtable = {}
+command = registrar.command(cmdtable)
+
+@command('info')
+
 def info(ui, repo):
     """Print information about the repository"""
     try:
@@ -18,17 +24,11 @@
         numrev = len(repo)

     ui.write(_("Repository: %s [hg root]\n") % (repo.root,))
-    ui.write(_("Base Hash: %s [hg id -r0]\n") % (hex(repo.changectx(0).node()),))
+    ui.write(_("Base Hash: %s [hg id -r0]\n") % (hex(repo.changelog.node(0)),))
     ui.write(_('Revisions: %s [hg tip --template "{rev}"]\n') % (numrev,))
-    ui.write(_("Files: %s [hg manifest | wc -l]\n") % (len(repo.changectx(numrev-1).manifest()),))
+    ui.write(_("Files: %s [hg manifest | wc -l]\n") % (len(repo[numrev-1].manifest()),))
     ui.write(_("Cloned From: %s [hg paths default]\n") % (ui.config('paths','default'),))
     default_push = ui.config('paths','default-push')
     if default_push:
         ui.write(_("Push To: %s [hg paths default-push]\n") % (default_push,))

-
-cmdtable = {
-    # "command-name": (function-call, options-list, help-string)
-    "info": (info, [], _("hg info"))
-}
-

Links


* [MercurialApi - Mercurial](https://www.mercurial-scm.org/wiki/MercurialApi)

2016年9月3日土曜日

Mercurialのhg histeditでやらかした時、unbundleで元に(近い状態に)戻す

概要

Mercurial (以下hg)には、履歴を改編する為のhisteditという拡張がある。

履歴を見易く綺麗にするには便利なのだが、うっかり「やらかして」しまったので、その顛末について残しておく。

やらかした内容


  • 関連のあるchangesetをまとめるためにhg histeditを実行した
  • 順序を変える必要があるのを忘れてうっかりeditor (vim)を終了
  • commit logの変更に進んでしまい、そこで:q!を実行してabortしたつもりがhisteditが実行された

復旧の手順


  • hg unbundleを使い、histeditを実行した際に保存されているbackup (bundle file)から復旧する
  • 実行するとheadsが2つに増えた。この状態でhisteditは使えないので、一旦rebaseして履歴をlinearにする
  • histeditを改めて実行して、commitを意図した順に並び換えた上で、不要なcommitをdrop

最後に


  • やらかしても慌てない
  • 自動backupと、hg unbundleは救世主 (間違ってstripした場合とかも戻せる)