def init_repo(p4, view_name, view_lock, charset=None, enable_mismatched_rhs=False, view_name_p4client=None, handle_imports=True): ''' Create view and repo if necessary. Does NOT copy p4 to the repo (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants. This is p4gf_auth_server's entry point into init_repo, called in response to a 'git clone'. view_name is the internal view_name with special chars already translated view_lock CounterLock mutex that prevents other processes from touching this repo, whether on this Git Fusion server or another. ''' LOG.debug("init_repo : view_name {1} view_name_p4client {1}".format( view_name, view_name_p4client)) client_name = p4gf_util.view_to_client_name(view_name) p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) result = _create_p4_client(p4, view_name, client_name, view_dirs.p4root, enable_mismatched_rhs, view_name_p4client, handle_imports) if result > INIT_REPO_OK: return result create_perm_groups(p4, view_name) with p4gf_context.create_context(view_name, view_lock) as ctx: p4gf_config.create_file_repo(ctx, view_name, charset) if ctx.client_exclusions_added: _print_stderr( _("The referenced client view contains implicit exclusions." "\nThe Git Fusion config will contain these as explicit exclusions." )) p4gf_copy_p2g.create_git_repo(ctx, view_dirs.GIT_DIR) create_p4_client_root(view_dirs.p4root) p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name) if result == INIT_REPO_OK: LOG.debug("repository creation for %s complete", view_name) # return the result of creating the client, to indicate if the client # had already been set up or not return result
def copy_p2g_ctx(ctx, start=None): """Using the given context, copy its view from Perforce to Git. Common code for p4gf_auth_server.py and p4gf_init_repo.py for setting up the eventual call to copy_p2g.""" view_name = ctx.config.view_name # Find directory paths to feed to git. p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4gf) ctx.view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) # cd into the work directory. Not all git functions react well to --work-tree=xxxx. os.chdir(ctx.view_dirs.GIT_WORK_TREE) # Fill git with content from Perforce. copy_p2g(ctx, start)
def _list_for_server(): ''' Return list of repos that have been copied to the given Git Fusion server. "have been copied" here means "has a .git-fusion/views/<view_name>/ directory on this server." ''' p4 = p4gf_create_p4.create_p4(client=p4gf_util.get_object_client_name()) result = [] p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) for view_name in p4gf_util.view_list(p4): view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) if os.path.exists(view_dirs.GIT_DIR): result.append(view_name) p4gf_create_p4.destroy(p4) return result
def init_repo(p4 , view_name , view_lock , charset=None , enable_mismatched_rhs=False , view_name_p4client=None , handle_imports=True): ''' Create view and repo if necessary. Does NOT copy p4 to the repo (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants. This is p4gf_auth_server's entry point into init_repo, called in response to a 'git clone'. view_name is the internal view_name with special chars already translated view_lock CounterLock mutex that prevents other processes from touching this repo, whether on this Git Fusion server or another. ''' LOG.debug("init_repo : view_name {1} view_name_p4client {1}".format( view_name, view_name_p4client)) client_name = p4gf_util.view_to_client_name(view_name) p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) result = _create_p4_client(p4, view_name, client_name, view_dirs.p4root, enable_mismatched_rhs, view_name_p4client, handle_imports) if result > INIT_REPO_OK: return result create_perm_groups(p4, view_name) with p4gf_context.create_context(view_name, view_lock) as ctx: p4gf_config.create_file_repo(ctx, view_name, charset) if ctx.client_exclusions_added: _print_stderr(_("The referenced client view contains implicit exclusions." "\nThe Git Fusion config will contain these as explicit exclusions.")) p4gf_copy_p2g.create_git_repo(ctx, view_dirs.GIT_DIR) create_p4_client_root(view_dirs.p4root) p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name) if result == INIT_REPO_OK: LOG.debug("repository creation for %s complete", view_name) # return the result of creating the client, to indicate if the client # had already been set up or not return result
def _read_user_map(self): """ Reads the user map file from Perforce into a list of tuples, consisting of username, email address, and full name. If no such file exists, an empty list is returned. Returns a list of 3-tuples: (p4user, email, fullname) """ usermap = [] root = p4gf_util.p4_to_p4gf_dir(self.p4) mappath = root + '/users/p4gf_usermap' global _user_map_synced if not _user_map_synced: # don't let a writable usermap file get in our way self.p4.run('sync', '-fq', mappath) _user_map_synced = True if not os.path.exists(mappath): return usermap with open(mappath) as mf: no_folding = self._is_case_sensitive() for line in mf: if not line: continue line = line.strip() if not line or line[0] == '#': continue m = USERMAP_REGEX.search(line) if not m: LOG.debug('No match: {}'.format(line)) continue p4user = m.group(1) if no_folding else m.group(1).casefold() email = m.group(2) _validate_email(email) fullname = p4gf_util.dequote(m.group(3)) usermap.append((p4user, email, fullname)) return usermap
def cleanup_client(ctx, view_name): """Clean up the failed client and workspace after an error occurs while creating the initial clone. If the client does not exist, nothing is done. """ client_name = p4gf_const.P4GF_CLIENT_PREFIX + view_name if not p4gf_util.spec_exists(ctx.p4, 'client', client_name): return LOG.debug('cleaning up failed view {}'.format(view_name)) command_path = ctx.client_view_path() p4gf_dir = p4gf_util.p4_to_p4gf_dir(ctx.p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) ctx.p4.run('sync', '-fq', command_path + '#none') ctx.p4.run('client', '-df', client_name) for vdir in [view_dirs.view_container]: LOG.debug('removing view directory {}'.format(vdir)) if os.path.isdir(vdir): shutil.rmtree(vdir) elif os.path.isfile(vdir): os.remove(vdir)
def init_repo(p4, view_name): """Create view and repo if necessary. Does NOT copy p4 to the repo (that's p4gf_copy_p2g's job). Returns one of the INIT_REPO_* constants. """ client_name = p4gf_context.view_to_client_name(view_name) p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) result = create_p4_client(p4, view_name, client_name, view_dirs.p4root) if result > INIT_REPO_OK: return result create_perm_groups(p4, view_name) p4gf_copy_p2g.create_git_repo(view_dirs.GIT_DIR) ensure_deny_rewind(view_dirs.GIT_WORK_TREE) install_hook(view_dirs.GIT_DIR) create_p4_client_root(view_dirs.p4root) p4gf_rc.update_file(view_dirs.rcfile, client_name, view_name) LOG.debug("repository creation for %s complete", view_name) # return the result of creating the client, to indicate if the client # had already been set up or not return result
def delete_client(args, p4, client_name): """Delete the named Perforce client and its workspace. Raises P4Exception if the client is not present, or the client configuration is not set up as expected. Keyword arguments: args -- parsed command line arguments p4 -- Git user's Perforce client client_name -- name of client to be deleted """ group_list = [ p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH ] p4.user = p4gf_const.P4GF_USER print_verbose(args, "Checking for client {}...".format(client_name)) if not p4gf_util.spec_exists(p4, 'client', client_name): raise P4.P4Exception('No such client "{}" defined'.format(client_name)) view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):] view_lock = None # We're clobbering and deleting. Overrule locks. try: ctx = p4gf_context.create_context(view_name, view_lock) except RuntimeError: # not a conforming Git Fusion client, ignore it return command_path = ctx.client_view_path() p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) rm_list = [view_dirs.view_container] homedir = os.path.expanduser('~') raise_if_homedir(homedir, view_name, rm_list) # Scan for objects associated only with this view so we can either remove # them completely or update their 'views' attribute appropriately. p4.handler = FilterViewFstatHandler(view_name) p4.run("fstat", "-Oa", "-T", "depotFile, attr-views", "//.git-fusion/objects/...") objects_to_delete = p4.handler.files_to_delete objects_to_modify = p4.handler.files_to_modify p4.handler = None if not args.delete: print("p4 sync -f {}#none".format(command_path)) print("p4 client -f -d {}".format(client_name)) for d in rm_list: print("rm -rf {}".format(d)) for to_delete in objects_to_delete: print("p4 obliterate -y {}".format(to_delete)) if objects_to_modify: for (fname, views) in objects_to_modify: print("attribute -p -n views -v {} {}".format(views, fname)) for group_template in group_list: group = group_template.format(view=view_name) print("p4 group -a -d {}".format(group)) print('p4 counter -u -d {}'.format( p4gf_lock.view_lock_name(view_name))) else: print_verbose(args, "Removing client files for {}...".format(client_name)) ctx.p4.run('sync', '-fq', command_path + '#none') print_verbose(args, "Deleting client {}...".format(client_name)) p4.run('client', '-df', client_name) for d in rm_list: remove_file_or_dir(args, view_name, d) bite_size = 1000 while len(objects_to_delete): to_delete = objects_to_delete[:bite_size] objects_to_delete = objects_to_delete[bite_size:] p4.run("obliterate", "-y", to_delete) if objects_to_modify: for (fname, views) in objects_to_modify: p4.run("edit", fname) p4.run("attribute", "-p", "-n", "views", "-v", views, fname) p4.run("submit", "-d", "'Removing {} from views attribute'".format(view_name)) for group_template in group_list: delete_group(args, p4, group_template.format(view=view_name)) _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
def delete_client(args, p4, client_name): """Delete the named Perforce client and its workspace. Raises P4Exception if the client is not present, or the client configuration is not set up as expected. Keyword arguments: args -- parsed command line arguments p4 -- Git user's Perforce client client_name -- name of client to be deleted """ group_list = [p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH] p4.user = p4gf_const.P4GF_USER print_verbose(args, "Checking for client {}...".format(client_name)) if not p4gf_util.spec_exists(p4, 'client', client_name): raise P4.P4Exception('No such client "{}" defined' .format(client_name)) view_name = client_name[len(p4gf_const.P4GF_CLIENT_PREFIX):] view_lock = None # We're clobbering and deleting. Overrule locks. try: ctx = p4gf_context.create_context(view_name, view_lock) except RuntimeError: # not a conforming Git Fusion client, ignore it return command_path = ctx.client_view_path() p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) rm_list = [view_dirs.view_container] homedir = os.path.expanduser('~') raise_if_homedir(homedir, view_name, rm_list) # Scan for objects associated only with this view so we can either remove # them completely or update their 'views' attribute appropriately. p4.handler = FilterViewFstatHandler(view_name) p4.run("fstat", "-Oa", "-T", "depotFile, attr-views", "//.git-fusion/objects/...") objects_to_delete = p4.handler.files_to_delete objects_to_modify = p4.handler.files_to_modify p4.handler = None if not args.delete: print("p4 sync -f {}#none".format(command_path)) print("p4 client -f -d {}".format(client_name)) for d in rm_list: print("rm -rf {}".format(d)) for to_delete in objects_to_delete: print("p4 obliterate -y {}".format(to_delete)) if objects_to_modify: for (fname, views) in objects_to_modify: print("attribute -p -n views -v {} {}".format(views, fname)) for group_template in group_list: group = group_template.format(view=view_name) print("p4 group -a -d {}".format(group)) print('p4 counter -u -d {}'.format(p4gf_lock.view_lock_name(view_name))) else: print_verbose(args, "Removing client files for {}...".format(client_name)) ctx.p4.run('sync', '-fq', command_path + '#none') print_verbose(args, "Deleting client {}...".format(client_name)) p4.run('client', '-df', client_name) for d in rm_list: remove_file_or_dir(args, view_name, d) bite_size = 1000 while len(objects_to_delete): to_delete = objects_to_delete[:bite_size] objects_to_delete = objects_to_delete[bite_size:] p4.run("obliterate", "-y", to_delete) if objects_to_modify: for (fname, views) in objects_to_modify: p4.run("edit", fname) p4.run("attribute", "-p", "-n", "views", "-v", views, fname) p4.run("submit", "-d", "'Removing {} from views attribute'".format(view_name)) for group_template in group_list: delete_group(args, p4, group_template.format(view=view_name)) _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
def delete_client(args, p4, client_name, metrics, prune_objs=True): """Delete the named Perforce client and its workspace. Raises P4Exception if the client is not present, or the client configuration is not set up as expected. Keyword arguments: args -- parsed command line arguments p4 -- Git user's Perforce client client_name -- name of client to be deleted metrics -- DeletionMetrics for collecting resulting metrics prune_objs -- if True, delete associated objects from cache """ # pylint: disable=R0912,R0915 group_list = [ p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH ] p4.user = p4gf_const.P4GF_USER print_verbose(args, _("Checking for client '{}'...").format(client_name)) if not p4gf_util.spec_exists(p4, 'client', client_name): raise P4.P4Exception( _("No such client '{}' defined").format(client_name)) view_name = p4gf_util.client_to_view_name(client_name) p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root': view_dirs.p4root}) view_lock = None # We're clobbering and deleting. Overrule locks. with p4gf_context.create_context(view_name, view_lock) as ctx: command_path = ctx.client_view_path() homedir = os.path.expanduser('~') raise_if_homedir(homedir, view_name, view_dirs.view_container) # Scan for objects associated only with this view so we can remove them. objects_to_delete = [] if prune_objs: objects_to_delete = _find_client_commit_objects( args, p4, view_name) # Do we have a repo config file to delete? config_file = p4gf_config.depot_path_repo(view_name) + '*' config_file_exists = p4gf_util.depot_file_exists(p4, config_file) # What counters shall we delete? counter_list = [] counter_list.append( p4gf_context.calc_last_copied_change_counter_name( view_name, p4gf_util.get_server_id())) for spec in p4.run('counters', '-u', '-e', "git-fusion-index-last-{},*".format(view_name)): counter_list.append(spec['counter']) for spec in p4.run('counters', '-u', '-e', "git-fusion-index-branch-{},*".format(view_name)): counter_list.append(spec['counter']) if not args.delete: print(NTR('p4 sync -f {}#none').format(command_path)) print(NTR('p4 client -f -d {}').format(client_name)) print(NTR('rm -rf {}').format(view_dirs.view_container)) print( NTR('Deleting {} objects from //{}/objects/...').format( len(objects_to_delete), p4gf_const.P4GF_DEPOT)) for group_template in group_list: group = group_template.format(view=view_name) print(NTR('p4 group -a -d {}').format(group)) for c in counter_list: print(NTR('p4 counter -u -d {}').format(c)) if config_file_exists: print(NTR('p4 sync -f {}').format(config_file)) print(NTR('p4 delete {}').format(config_file)) print( NTR('p4 submit -d "Delete repo config for {view_name}" {config_file}' ).format(view_name=view_name, config_file=config_file)) else: print_verbose( args, NTR('Removing client files for {}...').format(client_name)) ctx.p4.run('sync', '-fq', command_path + '#none') print_verbose(args, NTR('Deleting client {}...').format(client_name)) p4.run('client', '-df', client_name) metrics.clients += 1 print_verbose( args, NTR("Deleting repo {0}'s directory {1}...").format( view_name, view_dirs.view_container)) _remove_tree(view_dirs.view_container, contents_only=False) metrics.files += _delete_files(p4, objects_to_delete, view_name) for group_template in group_list: _delete_group(args, p4, group_template.format(view=view_name), metrics) for c in counter_list: _delete_counter(p4, c, metrics) if config_file_exists: p4gf_util.p4run_logged(p4, ['sync', '-fq', config_file]) with p4gf_util.NumberedChangelist( p4=p4, description=_("Delete repo config for '{}'").format( view_name)) as nc: nc.p4run(["delete", config_file]) nc.submit()
def delete_client(args, p4, client_name, metrics, prune_objs=True): """Delete the named Perforce client and its workspace. Raises P4Exception if the client is not present, or the client configuration is not set up as expected. Keyword arguments: args -- parsed command line arguments p4 -- Git user's Perforce client client_name -- name of client to be deleted metrics -- DeletionMetrics for collecting resulting metrics prune_objs -- if True, delete associated objects from cache """ # pylint: disable=R0912,R0915 group_list = [p4gf_const.P4GF_GROUP_VIEW_PULL, p4gf_const.P4GF_GROUP_VIEW_PUSH] p4.user = p4gf_const.P4GF_USER print_verbose(args, _("Checking for client '{}'...").format(client_name)) if not p4gf_util.spec_exists(p4, 'client', client_name): raise P4.P4Exception(_("No such client '{}' defined") .format(client_name)) view_name = p4gf_util.client_to_view_name(client_name) p4gf_dir = p4gf_util.p4_to_p4gf_dir(p4) view_dirs = p4gf_view_dirs.from_p4gf_dir(p4gf_dir, view_name) p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root': view_dirs.p4root}) view_lock = None # We're clobbering and deleting. Overrule locks. with p4gf_context.create_context(view_name, view_lock) as ctx: command_path = ctx.client_view_path() homedir = os.path.expanduser('~') raise_if_homedir(homedir, view_name, view_dirs.view_container) # Scan for objects associated only with this view so we can remove them. objects_to_delete = [] if prune_objs: objects_to_delete = _find_client_commit_objects(args, p4, view_name) # Do we have a repo config file to delete? config_file = p4gf_config.depot_path_repo(view_name) + '*' config_file_exists = p4gf_util.depot_file_exists(p4, config_file) # What counters shall we delete? counter_list = [] counter_list.append(p4gf_context.calc_last_copied_change_counter_name( view_name, p4gf_util.get_server_id())) for spec in p4.run('counters', '-u', '-e', "git-fusion-index-last-{},*" .format(view_name)): counter_list.append(spec['counter']) for spec in p4.run('counters', '-u', '-e', "git-fusion-index-branch-{},*" .format(view_name)): counter_list.append(spec['counter']) if not args.delete: print(NTR('p4 sync -f {}#none').format(command_path)) print(NTR('p4 client -f -d {}').format(client_name)) print(NTR('rm -rf {}').format(view_dirs.view_container)) print(NTR('Deleting {} objects from //{}/objects/...').format( len(objects_to_delete), p4gf_const.P4GF_DEPOT)) for group_template in group_list: group = group_template.format(view=view_name) print(NTR('p4 group -a -d {}').format(group)) for c in counter_list: print(NTR('p4 counter -u -d {}').format(c)) if config_file_exists: print(NTR('p4 sync -f {}').format(config_file)) print(NTR('p4 delete {}').format(config_file)) print(NTR('p4 submit -d "Delete repo config for {view_name}" {config_file}') .format(view_name=view_name, config_file=config_file)) else: print_verbose(args, NTR('Removing client files for {}...').format(client_name)) ctx.p4.run('sync', '-fq', command_path + '#none') print_verbose(args, NTR('Deleting client {}...').format(client_name)) p4.run('client', '-df', client_name) metrics.clients += 1 print_verbose(args, NTR("Deleting repo {0}'s directory {1}...").format(view_name, view_dirs.view_container)) _remove_tree(view_dirs.view_container, contents_only=False) metrics.files += _delete_files(p4, objects_to_delete, view_name) for group_template in group_list: _delete_group(args, p4, group_template.format(view=view_name), metrics) for c in counter_list: _delete_counter(p4, c, metrics) if config_file_exists: p4gf_util.p4run_logged(p4, ['sync', '-fq', config_file]) with p4gf_util.NumberedChangelist( p4=p4, description=_("Delete repo config for '{}'") .format(view_name)) as nc: nc.p4run(["delete", config_file]) nc.submit()