def test_pull_show_base(self): """brz pull supports --show-base see https://bugs.launchpad.net/bzr/+bug/202374""" # create two trees with conflicts, setup conflict, check that # conflicted file looks correct a_tree = self.example_branch('a') b_tree = a_tree.controldir.sprout('b').open_workingtree() with open(osutils.pathjoin('a', 'hello'), 'wt') as f: f.write('fee') a_tree.commit('fee') with open(osutils.pathjoin('b', 'hello'), 'wt') as f: f.write('fie') out, err = self.run_bzr(['pull', '-d', 'b', 'a', '--show-base']) # check for message here self.assertEqual( err, ' M hello\nText conflict in hello\n1 conflicts encountered.\n') self.assertEqualDiff( '<<<<<<< TREE\n' 'fie||||||| BASE-REVISION\n' 'foo=======\n' 'fee>>>>>>> MERGE-SOURCE\n', open(osutils.pathjoin('b', 'hello')).read())
def merge_text(self, params): """Calls msgmerge when .po files conflict. This requires a valid .pot file to reconcile both sides. """ # Create tmp files with the 'this' and 'other' content tmpdir = tempfile.mkdtemp(prefix='po_merge') env = {} env['this'] = osutils.pathjoin(tmpdir, 'this') env['other'] = osutils.pathjoin(tmpdir, 'other') env['result'] = osutils.pathjoin(tmpdir, 'result') env['pot_file'] = self.pot_file_abspath try: with osutils.open_file(env['this'], 'wb') as f: f.writelines(params.this_lines) with osutils.open_file(env['other'], 'wb') as f: f.writelines(params.other_lines) command = self.conf.expand_options(self.command, env) retcode, out, err = self._invoke(command) with osutils.open_file(env['result'], 'rb') as f: # FIXME: To avoid the list() construct below which means the # whole 'result' file is kept in memory, there may be a way to # use an iterator that will close the file when it's done, but # there is still the issue of removing the tmp dir... # -- vila 2011-11-24 return 'success', list(f.readlines()) finally: osutils.rmtree(tmpdir) return 'not applicable', []
def file_matches(self, params): """Return True if merge_matching should be called on this file.""" if not self.po_dirs or not self.command: # Return early if there is no options defined return False po_dir = None po_path = params.this_path for po_dir in self.po_dirs: glob = osutils.pathjoin(po_dir, self.po_glob) if fnmatch.fnmatch(po_path, glob): trace.mutter('po %s matches: %s' % (po_path, glob)) break else: trace.mutter('PoMerger did not match for %s and %s' % (self.po_dirs, self.po_glob)) return False # Do we have the corresponding .pot file for path, file_class, kind, entry in self.merger.this_tree.list_files( from_dir=po_dir, recursive=False): if fnmatch.fnmatch(path, self.pot_glob): relpath = osutils.pathjoin(po_dir, path) self.pot_file_abspath = self.merger.this_tree.abspath(relpath) # FIXME: I can't find an easy way to know if the .pot file has # conflicts *during* the merge itself. So either the actual # content on disk is fine and msgmerge will work OR it's not # and it will fail. Conversely, either the result is ok for the # user and he's happy OR the user needs to resolve the # conflicts in the .pot file and use remerge. # -- vila 2011-11-24 trace.mutter('will msgmerge %s using %s' % (po_path, self.pot_file_abspath)) return True else: return False
def test_pull(self): # Make sure we can pull from paths that can't be encoded dirname1 = self.info['directory'] dirname2 = self.info['directory'] + '2' url1 = urlutils.local_path_to_url(dirname1) url2 = urlutils.local_path_to_url(dirname2) out_bzrdir = self.wt.controldir.sprout(url1) out_bzrdir.sprout(url2) self.build_tree_contents([(osutils.pathjoin(dirname1, "a"), b'different text\n')]) self.wt.commit('mod a') txt = self.run_bzr_decode('pull', working_dir=dirname2) expected = osutils.pathjoin(osutils.getcwd(), dirname1) self.assertEqual( u'Using saved parent location: %s/\n' 'No revisions or tags to pull.\n' % (expected, ), txt) self.build_tree_contents([(osutils.pathjoin(dirname1, 'a'), b'and yet more\n')]) self.wt.commit(u'modifying a by ' + self.info['committer']) # We should be able to pull, even if our encoding is bad self.run_bzr_decode('pull --verbose', encoding='ascii', working_dir=dirname2)
def get_export_names(self): ret = [] for (dirpath, dirnames, filenames) in os.walk('output'): for dirname in dirnames: ret.append(osutils.pathjoin(dirpath, dirname)) for filename in filenames: ret.append(osutils.pathjoin(dirpath, filename)) return ret
def dir_grep(tree, path, relpath, opts, revno, path_prefix): # setup relpath to open files relative to cwd rpath = relpath if relpath: rpath = osutils.pathjoin('..', relpath) from_dir = osutils.pathjoin(relpath, path) if opts.from_root: # start searching recursively from root from_dir = None recursive = True to_grep = [] to_grep_append = to_grep.append # GZ 2010-06-05: The cache dict used to be recycled every call to dir_grep # and hits manually refilled. Could do this again if it was # for a good reason, otherwise cache might want purging. outputter = opts.outputter for fp, fc, fkind, entry in tree.list_files( include_root=False, from_dir=from_dir, recursive=opts.recursive): if _skip_file(opts.include, opts.exclude, fp): continue if fc == 'V' and fkind == 'file': tree_path = osutils.pathjoin(from_dir if from_dir else '', fp) if revno is not None: # If old result is valid, print results immediately. # Otherwise, add file info to to_grep so that the # loop later will get chunks and grep them cache_id = tree.get_file_revision(tree_path) if cache_id in outputter.cache: # GZ 2010-06-05: Not really sure caching and re-outputting # the old path is really the right thing, # but it's what the old code seemed to do outputter.write_cached_lines(cache_id, revno) else: to_grep_append((tree_path, (fp, tree_path))) else: # we are grepping working tree. if from_dir is None: from_dir = '.' path_for_file = osutils.pathjoin(tree.basedir, from_dir, fp) if opts.files_with_matches or opts.files_without_match: # Optimize for wtree list-only as we don't need to read the # entire file with open(path_for_file, 'rb', buffering=4096) as file: _file_grep_list_only_wtree(file, fp, opts, path_prefix) else: with open(path_for_file, 'rb') as f: _file_grep(f.read(), fp, opts, revno, path_prefix) if revno is not None: # grep versioned files for (path, tree_path), chunks in tree.iter_files_bytes(to_grep): path = _make_display_path(relpath, path) _file_grep(b''.join(chunks), path, opts, revno, path_prefix, tree.get_file_revision(tree_path))
def example_branch(self, path='.'): tree = self.make_branch_and_tree(path) self.build_tree_contents([(osutils.pathjoin(path, 'hello'), b'foo'), (osutils.pathjoin(path, 'goodbye'), b'baz')]) tree.add('hello') tree.commit(message='setup') tree.add('goodbye') tree.commit(message='setup') return tree
def tree_drop_mia_uploaders(local_tree, subpath, update_changelog=None, committer=None): control_path = local_tree.abspath( osutils.pathjoin(subpath, "debian/control")) changelog_entries = [] with ControlEditor(path=control_path) as editor: source = editor.source["Source"] bugs = all_mia_teammaint_bugs().intersection(get_package_bugs(source)) if not bugs: raise ChangerError("nothing-to-do", "No MIA people") removed_uploaders = [] fixed_bugs = [] for bug in bugs: mia_people = get_mia_maintainers(bug) if mia_people is None: logging.warning('No MIA people (X-Debbugs-CC) found in bug %d', bug) continue removed_mia = drop_uploaders(editor, mia_people) if len(removed_mia) == 0: continue if len(removed_mia) == 1: description = "Remove MIA uploader %s." % removed_mia[0] else: description = "Remove MIA uploaders %s." % ( ", ".join(removed_mia)) if removed_mia == mia_people: description += " Closes: #%d" % bug changelog_entries.append(description) removed_uploaders.extend(removed_mia) if not changelog_entries: return MIAResult(source, removed_uploaders=[], bugs=fixed_bugs) if update_changelog in (True, None): add_changelog_entry( local_tree, osutils.pathjoin(subpath, "debian/changelog"), changelog_entries, ) local_tree.commit("Remove MIA uploaders.", committer=committer, allow_pointless=False) return MIAResult(source, removed_uploaders=removed_uploaders, bugs=fixed_bugs)
def get_source_files(self, extensions=None): """Yield all source files for bzr and breezy :param our_files_only: If true, exclude files from included libraries or plugins. """ breezy_dir = self.get_breezy_dir() if extensions is None: extensions = ('.py', ) # This is the front-end 'bzr' script bzr_path = self.get_brz_path() yield bzr_path for root, dirs, files in os.walk(breezy_dir): for d in dirs: if d.endswith('.tmp'): dirs.remove(d) for f in files: for extension in extensions: if f.endswith(extension): break else: # Did not match the accepted extensions continue yield osutils.pathjoin(root, f)
def _default_to_location(self, from_location): """Work out a good To location give a From location. :return: the To location or None if unsure """ # We want to avoid opening the from location here so # we 'guess' the basename using some simple heuristics from_location = from_location.replace('\\', '/').rstrip('/') if from_location.find('/') >= 0: basename = osutils.basename(from_location) else: # Handle 'directory services' like lp: ds_sep = from_location.find(':') if ds_sep >= 0: basename = from_location[ds_sep + 1:] else: return None # Calculate the To location and check it's not the same as the # From location. to_location = osutils.pathjoin(self.parent_dir, basename) if to_location == from_location: return None else: return to_location
def test_update_conflicts_returns_2(self): self.make_branch_and_tree('branch') # make two checkouts self.run_bzr('checkout --lightweight branch checkout') self.build_tree(['checkout/file']) self.run_bzr('add checkout/file') self.run_bzr('commit -m add-file checkout') self.run_bzr('checkout --lightweight branch checkout2') # now alter file in checkout with open('checkout/file', 'wt') as a_file: a_file.write('Foo') self.run_bzr('commit -m checnge-file checkout') # now checkout2 should be out of date # make a local change to file with open('checkout2/file', 'wt') as a_file: a_file.write('Bar') out, err = self.run_bzr('update checkout2', retcode=1) self.assertEqualDiff( ''' M file Text conflict in file 1 conflicts encountered. Updated to revision 2 of branch %s ''' % osutils.pathjoin( self.test_dir, 'branch', ), err) self.assertEqual('', out)
def _load_from_file(topic_name): """Load help from a file. Topics are expected to be txt files in breezy.help_topics. """ resource_name = osutils.pathjoin("en", "%s.txt" % (topic_name, )) return osutils.resource_string('breezy.help_topics', resource_name)
def _file_grep_list_only_wtree(file, path, opts, path_prefix=None): # test and skip binary files if b'\x00' in file.read(1024): if opts.verbose: trace.warning("Binary file '%s' skipped.", path) return file.seek(0) # search from beginning found = False if opts.fixed_string: pattern = opts.pattern.encode(_user_encoding, 'replace') for line in file: if pattern in line: found = True break else: # not fixed_string for line in file: if opts.patternc.search(line): found = True break if (opts.files_with_matches and found) or \ (opts.files_without_match and not found): if path_prefix and path_prefix != '.': # user has passed a dir arg, show that as result prefix path = osutils.pathjoin(path_prefix, path) opts.outputter.get_writer(path, None, None)()
def make_changes( self, local_tree, subpath, update_changelog, reporter, committer, base_proposal=None, ): base_revid = local_tree.last_revision() with ControlEditor.from_tree(local_tree, subpath) as updater: updater.source["Rules-Requires-Root"] = "no" result = RulesRequiresRootResult(updater.source["Source"]) if update_changelog in (True, None): add_changelog_entry( local_tree, osutils.pathjoin(subpath, "debian/changelog"), ["Set Rules-Requires-Root: no."], ) revid = local_tree.commit("Set Rules-Requires-Root.", committer=committer, allow_pointless=False) branches = [("main", None, base_revid, revid)] tags = [] return ChangerResult( description="Set Rules-Requires-Root", mutator=result, branches=branches, tags=tags, sufficient_for_proposal=True, proposed_commit_message="Set Rules-Requires-Root.", )
def test_repository_deprecation_warning_suppressed_locations(self): """Old formats give a warning""" self.make_obsolete_repo('foo') conf = config.LocationStack(osutils.pathjoin(self.test_dir, 'foo')) conf.set('suppress_warnings', 'format_deprecation') self.enable_deprecation_warning() out, err = self.run_bzr('status', working_dir='foo') self.check_warning(False)
def test_update_up_to_date_light_checkout(self): self.make_branch_and_tree('branch') self.run_bzr('checkout --lightweight branch checkout') out, err = self.run_bzr('update checkout') self.assertEqual( 'Tree is up to date at revision 0 of branch %s\n' % osutils.pathjoin(self.test_dir, 'branch'), err) self.assertEqual('', out)
def tree_set_changelog_version(tree: WorkingTree, build_version: Version, subpath: str) -> None: cl_path = osutils.pathjoin(subpath, "debian/changelog") with tree.get_file(cl_path) as f: cl = Changelog(f) if Version(str(cl.version) + "~") > build_version: return cl.version = build_version with open(tree.abspath(cl_path), "w") as f: cl.write_to_open_file(f)
def test_cd_dir_and_back_home(self): self.assertEqual(self.test_dir, osutils.getcwd()) self.run_script(""" $ mkdir dir $ cd dir """) self.assertEqual(osutils.pathjoin(self.test_dir, 'dir'), osutils.getcwd()) self.run_script('$ cd') self.assertEqual(self.test_dir, osutils.getcwd())
def onFileActivated(self, item, column): path = item.data(0, QtCore.Qt.UserRole) if path: # directory self.setDirectory(str(path)) else: # file basename = str(item.text(0)) filepath = osutils.pathjoin(self.currentDirectory, basename) url = QtCore.QUrl(filepath) QtGui.QDesktopServices.openUrl(url)
def test_file_path(self): # Create a directory structure fname = self.info['filename'] dirname = self.info['directory'] self.build_tree_contents([('base/', ), (osutils.pathjoin('base', '%s/' % (dirname, )), )]) self.wt.add('base') self.wt.add('base/' + dirname) path = osutils.pathjoin('base', dirname, fname) self._check_OSX_can_roundtrip(self.info['filename']) self.wt.rename_one(fname, path) self.wt.commit('moving things around') txt = self.run_bzr_decode(['file-path', path]) # TODO: jam 20060106 We don't support non-ascii file ids yet, # so there is nothing which would fail in ascii encoding # This *should* be retcode=3 txt = self.run_bzr_decode(['file-path', path], encoding='ascii')
def read_quilt_patches(tree, directory=DEFAULT_DEBIAN_PATCHES_DIR): """Read patch contents from quilt directory. Args: tree: Tree to read directory: Patch directory Returns: list of Patch objects """ series_path = osutils.pathjoin(directory, "series") try: series_lines = tree.get_file_lines(series_path) except NoSuchFile: return [] for entry in read_quilt_series(series_lines): if entry.quoted: continue # TODO(jelmer): Pass on options? with tree.get_file(osutils.pathjoin(directory, entry.name)) as f: for patch in parse_patches(f, allow_dirty=True, keep_dirty=False): yield patch
def _make_display_path(relpath, path): """Return path string relative to user cwd. Take tree's 'relpath' and user supplied 'path', and return path that can be displayed to the user. """ if relpath: # update path so to display it w.r.t cwd # handle windows slash separator path = osutils.normpath(osutils.pathjoin(relpath, path)) path = path.replace('\\', '/') path = path.replace(relpath + '/', '', 1) return path
def test_smoke_update_checkout_bound_branch_local_commits(self): # smoke test for doing an update of a checkout of a bound # branch with local commits. master = self.make_branch_and_tree('master') master.commit('first commit') # make a bound branch self.run_bzr('checkout master child') # check that out self.run_bzr('checkout --lightweight child checkout') # get an object form of the checkout to manipulate wt = workingtree.WorkingTree.open('checkout') # change master with open('master/file', 'wt') as a_file: a_file.write('Foo') master.add(['file']) master_tip = master.commit('add file') # change child with open('child/file_b', 'wt') as a_file: a_file.write('Foo') # get an object form of child child = workingtree.WorkingTree.open('child') child.add(['file_b']) child_tip = child.commit('add file_b', local=True) # check checkout with open('checkout/file_c', 'wt') as a_file: a_file.write('Foo') wt.add(['file_c']) # now, update checkout -> # get all three files and a pending merge. out, err = self.run_bzr('update checkout') self.assertEqual('', out) self.assertEqualDiff( """+N file_b All changes applied successfully. +N file All changes applied successfully. Updated to revision 2 of branch %s Your local commits will now show as pending merges with 'brz status', and can be committed with 'brz commit'. """ % osutils.pathjoin( self.test_dir, 'master', ), err) self.assertEqual([master_tip, child_tip], wt.get_parent_ids()) self.assertPathExists('checkout/file') self.assertPathExists('checkout/file_b') self.assertPathExists('checkout/file_c') self.assertTrue(wt.has_filename('file_c'))
def test_update_with_merges(self): # Test that 'brz update' works correctly when you have # an update in the master tree, and a lightweight checkout # which has merged another branch master = self.make_branch_and_tree('master') self.build_tree(['master/file']) master.add(['file']) master.commit('one', rev_id=b'm1') self.build_tree(['checkout1/']) checkout_dir = bzrdir.BzrDirMetaFormat1().initialize('checkout1') checkout_dir.set_branch_reference(master.branch) checkout1 = checkout_dir.create_workingtree(b'm1') # Create a second branch, with an extra commit other = master.controldir.sprout('other').open_workingtree() self.build_tree(['other/file2']) other.add(['file2']) other.commit('other2', rev_id=b'o2') # Create a new commit in the master branch self.build_tree(['master/file3']) master.add(['file3']) master.commit('f3', rev_id=b'm2') # Merge the other branch into checkout os.chdir('checkout1') self.run_bzr('merge ../other') self.assertEqual([b'o2'], checkout1.get_parent_ids()[1:]) # At this point, 'commit' should fail, because we are out of date self.run_bzr_error(["please run 'brz update'"], 'commit -m merged') # This should not report about local commits being pending # merges, because they were real merges out, err = self.run_bzr('update') self.assertEqual('', out) self.assertEqualDiff( '''+N file3 All changes applied successfully. Updated to revision 2 of branch %s ''' % osutils.pathjoin( self.test_dir, 'master', ), err) # The pending merges should still be there self.assertEqual([b'o2'], checkout1.get_parent_ids()[1:])
def gbp_conf_has_dch_section(tree: Tree, debian_path: str = "") -> Optional[bool]: try: gbp_conf_path = osutils.pathjoin(debian_path, "gbp.conf") gbp_conf_text = tree.get_file_text(gbp_conf_path) except NoSuchFile: return False try: import configparser except ImportError: return None else: parser = configparser.ConfigParser(defaults={}, strict=False) parser.read_string( gbp_conf_text.decode("utf-8", errors="replace"), gbp_conf_path ) return parser.has_section("dch")
def test_update_out_of_date_light_checkout(self): self.make_branch_and_tree('branch') # make two checkouts self.run_bzr('checkout --lightweight branch checkout') self.run_bzr('checkout --lightweight branch checkout2') self.build_tree(['checkout/file']) self.run_bzr('add checkout/file') self.run_bzr('commit -m add-file checkout') # now checkout2 should be out of date out, err = self.run_bzr('update checkout2') self.assertEqualDiff( '''+N file All changes applied successfully. Updated to revision 1 of branch %s ''' % osutils.pathjoin( self.test_dir, 'branch', ), err) self.assertEqual('', out)
def test_update_with_merge_merged_to_master(self): # Test that 'brz update' works correctly when you have # an update in the master tree, and a [lightweight or otherwise] # checkout which has merge a revision merged to master already. master = self.make_branch_and_tree('master') self.build_tree(['master/file']) master.add(['file']) master.commit('one', rev_id=b'm1') self.build_tree(['checkout1/']) checkout_dir = bzrdir.BzrDirMetaFormat1().initialize('checkout1') checkout_dir.set_branch_reference(master.branch) checkout1 = checkout_dir.create_workingtree(b'm1') # Create a second branch, with an extra commit other = master.controldir.sprout('other').open_workingtree() self.build_tree(['other/file2']) other.add(['file2']) other.commit('other2', rev_id=b'o2') # Merge the other branch into checkout - 'start reviewing a patch' checkout1.merge_from_branch(other.branch) self.assertEqual([b'o2'], checkout1.get_parent_ids()[1:]) # Create a new commit in the master branch - 'someone else lands its' master.merge_from_branch(other.branch) master.commit('f3', rev_id=b'm2') # This should not report about local commits being pending # merges, because they were real merges (but are now gone). # It should perhaps report on them. out, err = self.run_bzr('update', working_dir='checkout1') self.assertEqual('', out) self.assertEqualDiff( '''All changes applied successfully. Updated to revision 2 of branch %s ''' % osutils.pathjoin( self.test_dir, 'master', ), err) # The pending merges should still be there self.assertEqual([], checkout1.get_parent_ids()[1:])
def assertFilesListEqual(self, tree, expected, **kwargs): with tree.lock_read(): if tree.supports_file_ids: actual = [ (path, status, kind, ie.file_id) for path, status, kind, ie in tree.list_files(**kwargs) ] expected = [(path, status, kind, tree.path2id( osutils.pathjoin(kwargs.get('from_dir', ''), path))) for path, status, kind in expected] else: actual = [ (path, status, kind) for path, status, kind, ie in tree.list_files(**kwargs) ] expected = [(path, status, kind) for path, status, kind in expected] self.assertEqual(expected, actual)
def _changelog_stats(branch: Branch, history: int, debian_path: str): mixed = 0 changelog_only = 0 other_only = 0 dch_references = 0 with branch.lock_read(): graph = branch.repository.get_graph() revids, truncated = _greedy_revisions(graph, branch.last_revision(), history) revs = [] for revid, rev in branch.repository.iter_revisions(revids): if rev is None: # Ghost continue if "Git-Dch: " in rev.message: dch_references += 1 revs.append(rev) get_deltas = branch.repository.get_revision_deltas for delta in get_deltas(revs): filenames = set( [a.path[1] for a in delta.added] + [r.path[0] for r in delta.removed] + [r.path[0] for r in delta.renamed] + [r.path[1] for r in delta.renamed] + [m.path[0] for m in delta.modified] ) if not set( [ f for f in filenames if f.startswith(debian_path + '/') ] ): continue if osutils.pathjoin(debian_path, "changelog") in filenames: if len(filenames) > 1: mixed += 1 else: changelog_only += 1 else: other_only += 1 return (changelog_only, other_only, mixed, dch_references)
def test_mkdir_in_subdir(self): """'brz mkdir' operation in subdirectory""" self.make_branch_and_tree('.') self.run_bzr(['mkdir', 'dir']) self.assertTrue(os.path.isdir('dir')) self.log('Run mkdir in subdir') self.run_bzr(['mkdir', 'subdir'], working_dir='dir') self.assertTrue(os.path.isdir('dir/subdir')) wt = WorkingTree.open('.') delta = wt.changes_from(wt.basis_tree()) self.log('delta.added = %r' % delta.added) self.assertEqual(len(delta.added), 2) self.assertEqual(delta.added[0][0], 'dir') self.assertEqual(delta.added[1][0], pathjoin('dir', 'subdir')) self.assertFalse(delta.modified)