Merge lp:~a1s/bzr-externals/breezy into lp:bzr-externals

Proposed by Aleksandr Smyshliaev
Status: Needs review
Proposed branch: lp:~a1s/bzr-externals/breezy
Merge into: lp:bzr-externals
Diff against target: 660 lines (+282/-279)
4 files modified
__init__.py (+9/-9)
commands.py (+16/-18)
externals.py (+254/-249)
setup.py (+3/-3)
To merge this branch: bzr merge lp:~a1s/bzr-externals/breezy
Reviewer Review Type Date Requested Status
Eugene Tarasenko Pending
Review via email: mp+435589@code.launchpad.net

Commit message

Update for Breezy and Python3

Description of the change

- Change imports from bzrlib to breezy
- Use Python3 text file operations to read and write bzrmeta files
- Fix reading externals configuration from an InventoryTree
- Use command "brz ignore" instead of writing to IGNORE_FILENAME (Breezy doesn't export IGNORE_FILENAME)

To post a comment you must log in.

Unmerged revisions

59. By Aleksandr Smyshliaev

Fix adding external working tree to the ignore list

58. By Aleksandr Smyshliaev

Fix reading externals config from a revision tree: the argument for get_file_text() must be a path, not file id

57. By Aleksandr Smyshliaev

Normalize line endings

56. By Aleksandr Smyshliaev

fix import paths in the commands module

55. By Aleksandr Smyshliaev

use Python3 text mode for file operations

54. By Aleksandr Smyshliaev

Change imports from bzrlib to breezy

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '__init__.py'
--- __init__.py 2012-03-15 02:32:58 +0000
+++ __init__.py 2023-01-11 14:30:26 +0000
@@ -56,15 +56,15 @@
56 url directory [revisionspec]56 url directory [revisionspec]
57"""57"""
5858
59from bzrlib.lazy_import import lazy_import59from breezy.lazy_import import lazy_import
60lazy_import(globals(), """60lazy_import(globals(), """
61from bzrlib.plugins.externals import externals as lazy_externals61from breezy.plugins.externals import externals as lazy_externals
62from bzrlib.plugins.externals import commands as lazy_commands62from breezy.plugins.externals import commands as lazy_commands
63""")63""")
6464
65from bzrlib.branch import Branch65from breezy.branch import Branch
66from bzrlib.mutabletree import MutableTree66from breezy.mutabletree import MutableTree
67from bzrlib.commands import Command, plugin_cmds67from breezy.commands import Command, plugin_cmds
6868
69plugin_name = 'externals'69plugin_name = 'externals'
70version_info = (1, 3, 4, 'dev', 2)70version_info = (1, 3, 4, 'dev', 2)
@@ -115,7 +115,7 @@
115install_hooks()115install_hooks()
116116
117def register_commands():117def register_commands():
118 module = 'bzrlib.plugins.externals.commands'118 module = 'breezy.plugins.externals.commands'
119 plugin_cmds.register_lazy('cmd_externals_add',119 plugin_cmds.register_lazy('cmd_externals_add',
120 ['eadd'], module)120 ['eadd'], module)
121 plugin_cmds.register_lazy('cmd_externals_command',121 plugin_cmds.register_lazy('cmd_externals_command',
@@ -135,9 +135,9 @@
135def new_finished(self):135def new_finished(self):
136 old_finished(self)136 old_finished(self)
137 # clear line137 # clear line
138 from bzrlib.ui import ui_factory138 from breezy.ui import ui_factory
139 ui_factory.clear_term()139 ui_factory.clear_term()
140140
141from bzrlib.progress import ProgressTask141from breezy.progress import ProgressTask
142old_finished = ProgressTask.finished142old_finished = ProgressTask.finished
143ProgressTask.finished = new_finished143ProgressTask.finished = new_finished
144144
=== modified file 'commands.py'
--- commands.py 2012-03-15 02:32:58 +0000
+++ commands.py 2023-01-11 14:30:26 +0000
@@ -16,14 +16,14 @@
1616
17import os.path17import os.path
1818
19from bzrlib.osutils import getcwd, get_user_encoding, isdir, isfile, pathjoin, relpath19from breezy.osutils import getcwd, get_user_encoding, isdir, isfile, pathjoin, relpath
20from bzrlib.commands import Command, run_bzr_catch_user_errors20from breezy.commands import Command, run_bzr_catch_user_errors
21from bzrlib.option import Option21from breezy.option import Option
22from bzrlib.trace import is_quiet, note22from breezy.trace import is_quiet, note
23from bzrlib.bzrdir import BzrDir23from breezy.bzr.bzrdir import BzrDir
24from bzrlib.workingtree import WorkingTree24from breezy.workingtree import WorkingTree
2525
26import externals26from . import externals
2727
28_main_cwd = getcwd()28_main_cwd = getcwd()
29_main_base = None29_main_base = None
@@ -92,12 +92,10 @@
92 self._add_to_file(root, externals.SNAPSHOT_PATH, line)92 self._add_to_file(root, externals.SNAPSHOT_PATH, line)
9393
94 # add ignore mask94 # add ignore mask
95 from bzrlib import IGNORE_FILENAME95 run_bzr_catch_user_errors(['ignore', './' + to_location])
96 self._add_to_file(root, IGNORE_FILENAME, './' + to_location)
9796
98 # add config files to repository97 # add config files to repository
99 cmd = ['add',98 cmd = ['add',
100 '.bzrignore',
101 '.bzrmeta/externals',99 '.bzrmeta/externals',
102 '.bzrmeta/externals-snapshot']100 '.bzrmeta/externals-snapshot']
103 run_bzr_catch_user_errors(cmd)101 run_bzr_catch_user_errors(cmd)
@@ -112,7 +110,7 @@
112 content = ''110 content = ''
113 path = pathjoin(root, file_name)111 path = pathjoin(root, file_name)
114 if isfile(path):112 if isfile(path):
115 f = open(path, 'rU')113 f = open(path, 'rt', encoding='utf-8')
116 try:114 try:
117 content = f.read()115 content = f.read()
118 finally:116 finally:
@@ -121,8 +119,8 @@
121 # add at end of file the char '\n' if needed119 # add at end of file the char '\n' if needed
122 content += '\n'120 content += '\n'
123121
124 content += line.encode('utf-8') + '\n'122 content += line + '\n'
125 f = open(path, 'w')123 f = open(path, 'wt', encoding='utf-8')
126 try:124 try:
127 f.write(content)125 f.write(content)
128 finally:126 finally:
@@ -210,10 +208,10 @@
210 def _substitute_in_commandlist(self, command_list, rel_path):208 def _substitute_in_commandlist(self, command_list, rel_path):
211 return [x.replace('{relpath}', rel_path) for x in command_list]209 return [x.replace('{relpath}', rel_path) for x in command_list]
212210
213import bzrlib.builtins211import breezy.builtins
214212
215class cmd_branch(bzrlib.builtins.cmd_branch):213class cmd_branch(breezy.builtins.cmd_branch):
216 __doc__ = bzrlib.builtins.cmd_branch.__doc__214 __doc__ = breezy.builtins.cmd_branch.__doc__
217215
218 def plugin_name(self):216 def plugin_name(self):
219 return None217 return None
@@ -222,8 +220,8 @@
222 externals.command_kwargs = kwargs220 externals.command_kwargs = kwargs
223 super(cmd_branch, self).run(**kwargs)221 super(cmd_branch, self).run(**kwargs)
224222
225class cmd_checkout(bzrlib.builtins.cmd_checkout):223class cmd_checkout(breezy.builtins.cmd_checkout):
226 __doc__ = bzrlib.builtins.cmd_checkout.__doc__224 __doc__ = breezy.builtins.cmd_checkout.__doc__
227225
228 def plugin_name(self):226 def plugin_name(self):
229 return None227 return None
230228
=== modified file 'externals.py'
--- externals.py 2012-01-20 00:19:27 +0000
+++ externals.py 2023-01-11 14:30:26 +0000
@@ -1,249 +1,254 @@
1# Copyright (C) 2009 Eugene Tarasenko, Alexander Belchenko1# Copyright (C) 2009 Eugene Tarasenko, Alexander Belchenko
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.6# (at your option) any later version.
7#7#
8# This program is distributed in the hope that it will be useful,8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.11# GNU General Public License for more details.
12#12#
13# You should have received a copy of the GNU General Public License13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1616
17import os17import os
1818
19from bzrlib.urlutils import join, local_path_from_url19from breezy.urlutils import join, local_path_from_url
20from bzrlib.osutils import check_legal_path, getcwd, get_user_encoding, isdir, isfile, pathjoin, relpath20from breezy.osutils import check_legal_path, getcwd, get_user_encoding, isdir, isfile, pathjoin, relpath
21from bzrlib.commands import run_bzr_catch_user_errors21from breezy.commands import run_bzr_catch_user_errors
22from bzrlib.cmdline import split22from breezy.cmdline import split
23from bzrlib.trace import is_quiet, is_verbose, note, warning23from breezy.trace import is_quiet, is_verbose, note, warning
2424
25CONFIG_PATH = '.bzrmeta/externals'25CONFIG_PATH = '.bzrmeta/externals'
26SNAPSHOT_PATH = '.bzrmeta/externals-snapshot'26SNAPSHOT_PATH = '.bzrmeta/externals-snapshot'
2727
28disable_hooks = False # for prevent double running external command28disable_hooks = False # for prevent double running external command
29command_kwargs = None # each new command changed value29command_kwargs = None # each new command changed value
3030
31class Externals:31class Externals:
32 32
33 def __init__(self, branch, revid, root=None):33 def __init__(self, branch, revid, root=None):
34 self.branch = branch34 self.branch = branch
35 self.revid = revid35 self.revid = revid
36 if root is not None:36 if root is not None:
37 self.root = root37 self.root = root
38 else:38 else:
39 self.root = local_path_from_url(branch.base)39 self.root = local_path_from_url(branch.base)
40 self.cwd = getcwd()40 self.cwd = getcwd()
41 self.config = []41 self.config = []
42 self.bound = True42 self.bound = True
43 self.use_snapshot = command_kwargs and 'revision' in command_kwargs43 self.use_snapshot = command_kwargs and 'revision' in command_kwargs
4444
45 def _set_config(self, text):45 def _set_config(self, text):
46 lines = text.splitlines()46 lines = text.splitlines()
47 for line in lines:47 for line in lines:
48 if len(line.strip()) > 0 and not line.startswith('#'):48 if len(line.strip()) > 0 and not line.startswith('#'):
49 # function cmdline.split does not support windows path separator '\'49 # function cmdline.split does not support windows path separator '\'
50 line = line.decode('utf-8').replace('\\', '/')50 line = line.replace('\\', '/')
51 arg = split(line)51 arg = split(line)
52 if arg not in self.config:52 if arg not in self.config:
53 self.config.append(arg)53 self.config.append(arg)
5454
55 def read_config(self):55 def read_config(self):
56 path = pathjoin(self.root, CONFIG_PATH)56 path = pathjoin(self.root, CONFIG_PATH)
57 if self.use_snapshot or not isfile(path):57 if self.use_snapshot or not isfile(path):
58 # config file not exist in directory58 # config file not exist in directory
59 return False59 return False
60 f = open(path, 'rU')60 f = open(path, 'rt', encoding='utf-8')
61 try:61 try:
62 self._set_config(f.read())62 self._set_config(f.read())
63 finally:63 finally:
64 f.close()64 f.close()
65 return len(self.config) > 065 return len(self.config) > 0
66 66
67 def read_config_from_repository(self):67 def read_config_from_repository(self):
68 rev_tree = self.branch.repository.revision_tree(self.revid)68 rev_tree = self.branch.repository.revision_tree(self.revid)
69 if self.use_snapshot:69 if self.use_snapshot:
70 file_id = rev_tree.path2id(SNAPSHOT_PATH)70 if rev_tree.is_versioned(SNAPSHOT_PATH):
71 if not file_id:71 cfg_path = SHAPSHOT_PATH
72 file_id = rev_tree.path2id(CONFIG_PATH)72 else:
73 if file_id:73 cfg_path = CONFIG_PATH
74 warning('warning: for this revision there is no snapshot of external branches!')74 if rev_tree.is_versioned(cfg_path):
75 else:75 warning('warning: for this revision there is no snapshot of external branches!')
76 file_id = rev_tree.path2id(CONFIG_PATH)76 else:
77 if not file_id:77 cfg_path = None
78 # there is no config or snapshot files in repository78 else:
79 return False79 cfg_path = CONFIG_PATH
80 rev_tree.lock_read()80 if not rev_tree.is_versioned(cfg_path):
81 try:81 cfg_path = None
82 text = rev_tree.get_file_text(file_id)82 if not cfg_path:
83 self._set_config(text)83 # there is no config or snapshot files in repository
84 finally:84 return False
85 rev_tree.unlock()85 rev_tree.lock_read()
86 return len(self.config) > 086 try:
8787 text = rev_tree.get_file_text(cfg_path)
88 def _relpath(self, path):88 self._set_config(text.decode('utf-8'))
89 try:89 finally:
90 return relpath(self.cwd, path)90 rev_tree.unlock()
91 except:91 return len(self.config) > 0
92 pass92
93 return path93 def _relpath(self, path):
9494 try:
95 @staticmethod95 return relpath(self.cwd, path)
96 def _relurljoin(base, relative):96 except:
97 if relative.startswith('//'):97 pass
98 # urlutils.join not supports relative urls start with '//'98 return path
99 scheme = base.partition('://')99
100 return scheme[0] + ':' + relative100 @staticmethod
101 else:101 def _relurljoin(base, relative):
102 return join(base, relative)102 if relative.startswith('//'):
103103 # urlutils.join not supports relative urls start with '//'
104 @staticmethod104 scheme = base.partition('://')
105 def _report(cmd):105 return scheme[0] + ':' + relative
106 if not is_quiet():106 else:
107 note('External ' + ' '.join(cmd))107 return join(base, relative)
108108
109 @staticmethod109 @staticmethod
110 def adjust_verbosity(cmd):110 def _report(cmd):
111 if is_quiet():111 if not is_quiet():
112 cmd += ['-q']112 note('External ' + ' '.join(cmd))
113 if is_verbose():113
114 cmd += ['-v']114 @staticmethod
115115 def adjust_verbosity(cmd):
116 def branch_iterator(self, target_root=None):116 if is_quiet():
117 if len(self.config) == 0:117 cmd += ['-q']
118 # branch not have externals configuration118 if is_verbose():
119 return119 cmd += ['-v']
120120
121 self.bound = True121 def branch_iterator(self, target_root=None):
122 if not target_root:122 if len(self.config) == 0:
123 target_root = self.branch.get_bound_location()123 # branch not have externals configuration
124 if not target_root:124 return
125 self.bound = False125
126 target_root = self.branch.get_parent()126 self.bound = True
127 if not target_root:127 if not target_root:
128 # support new braches with no parent yet128 target_root = self.branch.get_bound_location()
129 target_root = self.branch.base129 if not target_root:
130130 self.bound = False
131 for arg in self.config: # url directory [revisionspec]131 target_root = self.branch.get_parent()
132 location = self._relurljoin(target_root, arg[0])132 if not target_root:
133 if target_root.startswith('file:///'):133 # support new braches with no parent yet
134 # try to pull externals from the parent for the feature branch134 target_root = self.branch.base
135 path = pathjoin(local_path_from_url(target_root), arg[1])135
136 if isdir(path):136 for arg in self.config: # url directory [revisionspec]
137 location = self._relpath(path)137 location = self._relurljoin(target_root, arg[0])
138 else:138 if target_root.startswith('file:///'):
139 # parent is local master branch139 # try to pull externals from the parent for the feature branch
140 if location.startswith('file:///'):140 path = pathjoin(local_path_from_url(target_root), arg[1])
141 location = self._relpath(local_path_from_url(location))141 if isdir(path):
142142 location = self._relpath(path)
143 check_legal_path(arg[1])143 else:
144 rel_path = self._relpath(pathjoin(self.root, arg[1]))144 # parent is local master branch
145 145 if location.startswith('file:///'):
146 revision = None146 location = self._relpath(local_path_from_url(location))
147 if len(arg) > 2:147
148 revision = arg[2]148 check_legal_path(arg[1])
149 yield location, rel_path, revision149 rel_path = self._relpath(pathjoin(self.root, arg[1]))
150150
151 def pull(self):151 revision = None
152 if disable_hooks:152 if len(arg) > 2:
153 return153 revision = arg[2]
154154 yield location, rel_path, revision
155 # need use merged config from repository and working tree155
156 # because new added external branch from repository or working tree156 def pull(self):
157 # need pull/update for correct snapshot157 if disable_hooks:
158 self.read_config()158 return
159 self.read_config_from_repository()159
160 if len(self.config) == 0:160 # need use merged config from repository and working tree
161 return161 # because new added external branch from repository or working tree
162 162 # need pull/update for correct snapshot
163 for location, path, revision in self.branch_iterator():163 self.read_config()
164 if location == path:164 self.read_config_from_repository()
165 # not create feature branch for directory above the root165 if len(self.config) == 0:
166 continue166 return
167167
168 # select what do it168 for location, path, revision in self.branch_iterator():
169 if isdir(pathjoin(path, '.bzr')) or isdir(pathjoin(path, '.svn')):169 if location == path:
170 if self.bound:170 # not create feature branch for directory above the root
171 cmd = ['update', path]171 continue
172 else:172
173 cmd = ['pull', location, '--directory', path]173 # select what do it
174 else:174 if isdir(pathjoin(path, '.bzr')) or isdir(pathjoin(path, '.svn')):
175 if self.bound:175 if self.bound:
176 cmd = ['checkout', location, path]176 cmd = ['update', path]
177 else:177 else:
178 cmd = ['branch', location, path]178 cmd = ['pull', location, '--directory', path]
179179 else:
180 # command branch don't create recursive directory180 if self.bound:
181 dirs = path.rpartition('/')181 cmd = ['checkout', location, path]
182 if dirs[0] != '' and not isdir(dirs[0]):182 else:
183 os.makedirs(dirs[0].encode(get_user_encoding()))183 cmd = ['branch', location, path]
184184
185 # if use revision options but not for 'update'185 # command branch don't create recursive directory
186 if revision is not None and cmd[0] != 'update':186 dirs = path.rpartition('/')
187 cmd += ['--revision', revision]187 if dirs[0] != '' and not isdir(dirs[0]):
188188 os.makedirs(dirs[0].encode(get_user_encoding()))
189 self.adjust_verbosity(cmd)189
190 self._report(cmd)190 # if use revision options but not for 'update'
191 run_bzr_catch_user_errors(cmd)191 if revision is not None and cmd[0] != 'update':
192192 cmd += ['--revision', revision]
193 def push(self, target):193
194 if disable_hooks or not self.read_config():194 self.adjust_verbosity(cmd)
195 return195 self._report(cmd)
196196 run_bzr_catch_user_errors(cmd)
197 for location, path, revision in self.branch_iterator(target):197
198 if location == path:198 def push(self, target):
199 # don't push into itself199 if disable_hooks or not self.read_config():
200 continue200 return
201201
202 # XXX: maybe he should rather decorate the push command202 for location, path, revision in self.branch_iterator(target):
203 # so that we can get the commandline args203 if location == path:
204 # alternatively the plugin infrastructure must provide it to us?!204 # don't push into itself
205 cmd = ['push', location, '--directory', path, '--no-strict']205 continue
206206
207 if revision is not None:207 # XXX: maybe he should rather decorate the push command
208 # not push if use revision 208 # so that we can get the commandline args
209 continue209 # alternatively the plugin infrastructure must provide it to us?!
210210 cmd = ['push', location, '--directory', path, '--no-strict']
211 self.adjust_verbosity(cmd)211
212 self._report(cmd)212 if revision is not None:
213 run_bzr_catch_user_errors(cmd)213 # not push if use revision
214214 continue
215 @staticmethod215
216 def _quoted_if_need(text):216 self.adjust_verbosity(cmd)
217 if text.find(' ') != -1:217 self._report(cmd)
218 text = '"' + text + '"'218 run_bzr_catch_user_errors(cmd)
219 return text219
220 220 @staticmethod
221 def commit(self, mutable_tree):221 def _quoted_if_need(text):
222 # BUG: not run recursively if in above branch not have changes 222 if text.find(' ') != -1:
223 if disable_hooks or not self.read_config():223 text = '"' + text + '"'
224 return224 return text
225225
226 from bzrlib.workingtree import WorkingTree226 def commit(self, mutable_tree):
227 snapshot = []227 # BUG: not run recursively if in above branch not have changes
228 for arg in self.config: # url directory [revisionspec]228 if disable_hooks or not self.read_config():
229 wt = WorkingTree.open(pathjoin(self.root, arg[1]))229 return
230 if wt.has_changes(wt.basis_tree()):230
231 cmd = ['ci']231 from breezy.workingtree import WorkingTree
232 os.chdir(wt.basedir)232 snapshot = []
233 try:233 for arg in self.config: # url directory [revisionspec]
234 run_bzr_catch_user_errors(cmd)234 wt = WorkingTree.open(pathjoin(self.root, arg[1]))
235 finally:235 if wt.has_changes(wt.basis_tree()):
236 os.chdir(self.cwd)236 cmd = ['ci']
237 237 os.chdir(wt.basedir)
238 if len(arg) < 3:238 try:
239 arg.append('') 239 run_bzr_catch_user_errors(cmd)
240 arg[2] = 'revid:' + wt.last_revision()240 finally:
241 arg[1] = self._quoted_if_need(arg[1])241 os.chdir(self.cwd)
242 snapshot.append(' '.join(arg).encode('utf-8'))242
243243 if len(arg) < 3:
244 path = pathjoin(self.root, SNAPSHOT_PATH)244 arg.append('')
245 f = open(path, 'w')245 arg[2] = 'revid:' + wt.last_revision()
246 try:246 arg[1] = self._quoted_if_need(arg[1])
247 f.write('\n'.join(snapshot))247 snapshot.append(' '.join(arg))
248 finally:248
249 f.close()249 path = pathjoin(self.root, SNAPSHOT_PATH)
250 f = open(path, 'wt', encoding='utf-8')
251 try:
252 f.write('\n'.join(snapshot))
253 finally:
254 f.close()
250255
=== modified file 'setup.py'
--- setup.py 2010-03-18 12:25:55 +0000
+++ setup.py 2023-01-11 14:30:26 +0000
@@ -22,7 +22,7 @@
22bzr_plugin_name = __init__.plugin_name22bzr_plugin_name = __init__.plugin_name
23bzr_commands = ['externals-add', 'externals-command']23bzr_commands = ['externals-add', 'externals-command']
24bzr_plugin_version = __init__.version_info24bzr_plugin_version = __init__.version_info
25bzr_minimum_version = (1, 4, 0)25bzr_minimum_version = (3, 0, 0)
26bzr_maximum_version = None26bzr_maximum_version = None
2727
28if __name__ == '__main__':28if __name__ == '__main__':
@@ -34,5 +34,5 @@
34 author_email="eugene.tarasenko@gmail.com",34 author_email="eugene.tarasenko@gmail.com",
35 license="GNU GPL v2",35 license="GNU GPL v2",
36 url="https://launchpad.net/bzr-externals",36 url="https://launchpad.net/bzr-externals",
37 packages=['bzrlib.plugins.externals', ],37 packages=['breezy.plugins.externals', ],
38 package_dir={'bzrlib.plugins.externals': '.'})38 package_dir={'breezy.plugins.externals': '.'})

Subscribers

People subscribed via source and target branches