def _create_client(p4, client_name, p4gf_dir): """Create the host-specific Perforce client to enable working with the object cache in the P4GF_DEPOT depot. """ # to prevent the mirrored git commit/tree objects from being retained in the # git-fusion workspace, set client option 'rmdir' and sync #none in p4gf_gitmirror # Assume the usual P4 client default options are being used so that # these options below differ ONLY with normdir -> rmdir # if this assumption proves troublesome, then read/write cycle will be needed. options = NTR('allwrite clobber nocompress unlocked nomodtime rmdir') view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=client_name)] spec_created = False if not p4gf_util.spec_exists(p4, 'client', client_name): # See if the old object clients exist, in which case we will remove them. for old_client_name in [OLD_OBJECT_CLIENT, OLDER_OBJECT_CLIENT]: if p4gf_util.spec_exists(p4, 'client', old_client_name): p4.run('client', '-df', old_client_name) _info(_("Old client '{}' deleted.").format(old_client_name)) spec_created = p4gf_util.ensure_spec( p4, 'client', spec_id=client_name, values={'Host': None, 'Root': p4gf_dir, 'Description': _('Created by Perforce Git Fusion'), 'Options': options, 'View': view}) if spec_created: _info(_("Client '{}' created.").format(client_name)) if not spec_created: modified = p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root': p4gf_dir, 'View': view, 'Options': options}) if modified: _info(_("Client '{}' updated.").format(client_name)) else: _info(_("Client '{}' already exists.").format(client_name))
def create_p4_client(p4, view_name, client_name, client_root): """Create the p4 client to contain Git meta-data mirror. Keyword arguments: p4 -- Perforce client API view_name -- client view of repository to clone client_name -- client that will be created client_root -- path for client workspace Returns one of the INIT_REPO_* constants. """ # Ensure the client root directory has been created. if not os.path.exists(client_root): os.makedirs(client_root) # If a client for this view already exists, we're probably done. # # Make sure the client root is correct. if p4gf_util.spec_exists(p4, 'client', client_name): LOG.debug("%s client already exists for %s", client_name, view_name) p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root':client_root}) return INIT_REPO_EXISTS # Client does not yet exist. We'll have to configure it manually, using # the view's name as a template. if not p4gf_util.spec_exists(p4, 'client', view_name): LOG.warn("requested client %s does not exist, required for creating a mirror", view_name) sys.stderr.write("View {} does not exist\n".format(view_name)) return INIT_REPO_NOVIEW # Seed a new client using the view's view as a template. LOG.info("client %s does not exist, creating from view %s", client_name, view_name) view = p4gf_util.first_value_for_key( p4.run('client', '-o', '-t', view_name, client_name), 'View') if not view_depots_ok(p4, view_name, view): # nature of problem already reported return INIT_REPO_BADVIEW desc = ("Created by Perforce Git Fusion for work in {view}." .format(view=view_name)) p4gf_util.set_spec(p4, 'client', spec_id=client_name, values={'Owner' : p4gf_const.P4GF_USER, 'LineEnd' : 'unix', 'View' : view, 'Root' : client_root, 'Host' : None, 'Description' : desc}) LOG.debug("successfully created client %s", client_name) return INIT_REPO_OK
def repo_from_template_client( p4, view_name, view_name_p4client, client_name , client_root, enable_mismatched_rhs): ''' Create a new Perforce client spec <client_name> using existing Perforce client spec <view_name> as a template (just use its View). ''' # view_name_p4client is the p4client # view_name is the gfinternal repo name # view_name differs from view_name_p4client if latter contains special chars # or was configured with --p4client argument if not p4gf_util.spec_exists(p4, 'client', view_name_p4client): return INIT_REPO_NOVIEW client = p4.run('client', '-o', view_name_p4client)[0] if 'Stream' in client: return _repo_from_stream(p4, view_name, client.get('Stream'), client_name, client_root, enable_mismatched_rhs) with Validator.from_template_client(view_name, p4, view_name_p4client) as validator: if not validator.is_valid(enable_mismatched_rhs): return INIT_REPO_CONFIG_FILE_BAD # Seed a new client using the view's view as a template. LOG.info("Git Fusion client %s does not exist," " creating from existing Perforce client %s" , client_name, view_name_p4client) view = p4gf_util.first_value_for_key( p4.run('client', '-o', '-t', view_name_p4client, client_name), 'View') create_repo_client(p4, view_name, client_name, client_root, view, None) return INIT_REPO_OK
def convert_client(args, p4, client_name): """Convert 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 old_client = p4.client p4.client = client_name print(" Processing 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):] client = p4.fetch_client() command_path = client["Root"] if not args.convert: print(" Removing client files for {}...".format(client_name)) print(" p4 sync -fqk {}/...#none".format(command_path)) print(" Create config for client {}...".format(client_name)) p4.client = old_client for group_template in group_list: group = group_template.format(view=view_name) print(" Leaving existing group {}".format(group)) print(" Remove client lock counter") print(" p4 counter -u -d {}".format( p4gf_lock.view_lock_name(view_name))) else: LOG_FILE.write("Processing client {}\n".format(client_name)) print(" Removing client files for {}...".format(client_name)) print(" p4 sync -fqk {}/...#none".format(command_path)) LOG_FILE.write("p4 sync -fqk {}/...#none\n".format(command_path)) p4.run('sync', '-fqk', command_path + '/...#none') print(" Creating config for client {}...".format(client_name)) LOG_FILE.write( "Creating config for client {}...\n".format(client_name)) p4.client = old_client create_from_12x_gf_client_name(p4, client_name) for group_template in group_list: group = group_template.format(view=view_name) print(" Leaving existing group {}".format(group)) print(" Remove client lock counter") print(" p4 counter -u -d {}".format( p4gf_lock.view_lock_name(view_name))) LOG_FILE.write("p4 counter -u -d {}\n".format( p4gf_lock.view_lock_name(view_name))) _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
def _create_client(p4, client_name, p4gf_dir): """Create the host-specific Perforce client to enable working with the object cache in the P4GF_DEPOT depot. """ # to prevent the mirrored git commit/tree objects from being retained in the # git-fusion workspace, set client option 'rmdir' and sync #none in p4gf_gitmirror # Assume the usual P4 client default options are being used so that # these options below differ ONLY with normdir -> rmdir # if this assumption proves troublesome, then read/write cycle will be needed. options = NTR('allwrite clobber nocompress unlocked nomodtime rmdir') view = [ '//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=client_name) ] spec_created = False if not p4gf_util.spec_exists(p4, 'client', client_name): # See if the old object clients exist, in which case we will remove them. for old_client_name in [OLD_OBJECT_CLIENT, OLDER_OBJECT_CLIENT]: if p4gf_util.spec_exists(p4, 'client', old_client_name): p4.run('client', '-df', old_client_name) _info(_("Old client '{}' deleted.").format(old_client_name)) spec_created = p4gf_util.ensure_spec( p4, 'client', spec_id=client_name, values={ 'Host': None, 'Root': p4gf_dir, 'Description': _('Created by Perforce Git Fusion'), 'Options': options, 'View': view }) if spec_created: _info(_("Client '{}' created.").format(client_name)) if not spec_created: modified = p4gf_util.ensure_spec_values(p4, 'client', client_name, { 'Root': p4gf_dir, 'View': view, 'Options': options }) if modified: _info(_("Client '{}' updated.").format(client_name)) else: _info(_("Client '{}' already exists.").format(client_name))
def _repo_from_stream(p4, view_name, stream_name, client_name, client_root, enable_mismatched_rhs, handle_imports=True): """Create a new client from the named stream. Create a new Perforce client spec <client_name> using existing Perforce stream spec <stream_name> as a template (just use its View). Returns one of the INIT_REPO_* constants. """ # stream_name is the name of a stream, e.g. '//depot/stream' # view_name is the gfinternal repo name if not p4gf_util.spec_exists(p4, 'stream', stream_name): return INIT_REPO_NOVIEW with Validator.from_stream(view_name, p4, stream_name) as validator: if not validator.is_valid(enable_mismatched_rhs): return INIT_REPO_CONFIG_FILE_BAD # Seed a new client using the stream's view as a template. LOG.info("Git Fusion client %s does not exist, creating from existing Perforce stream %s", client_name, stream_name) # Create virtual stream with excluded paths, use that for client. stream = p4.fetch_stream(stream_name) if handle_imports: config = p4gf_config.get_repo(p4, view_name) imports_enabled = p4gf_config.is_feature_enabled(config, p4gf_config.FEATURE_IMPORTS) else: imports_enabled = False if imports_enabled: stream_paths = p4gf_streams.stream_import_exclude(stream['Paths']) else: stream_paths = stream['Paths'] desc = (_("Created by Perforce Git Fusion for work in '{view}'.") .format(view=p4gf_translate.TranslateReponame.repo_to_git(view_name))) spec_values = { 'Owner': p4gf_const.P4GF_USER, 'Parent': stream_name, 'Type': 'virtual', 'Description': desc, 'Options': 'notoparent nofromparent', 'Paths': stream_paths, 'Remapped': ['.gitmodules-{} .gitmodules'.format(view_name)] } if imports_enabled: stream_name += '_p4gfv' p4gf_util.set_spec(p4, 'stream', spec_id=stream_name, values=spec_values) LOG.debug('virtual stream {} created for {}'.format(stream_name, client_name)) create_repo_client(p4, view_name, client_name, client_root, None, stream_name) return INIT_REPO_OK
def _create_client(p4, client_name, p4gf_dir): """Create the host-specific Perforce client to enable working with the object cache in the .git-fusion depot. """ view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=client_name)] spec_created = False if not p4gf_util.spec_exists(p4, "client", client_name): # See if the old object clients exist, in which case we will remove them. if p4gf_util.spec_exists(p4, "client", OLD_OBJECT_CLIENT): p4.run('client', '-df', OLD_OBJECT_CLIENT) if p4gf_util.spec_exists(p4, "client", OLDER_OBJECT_CLIENT): p4.run('client', '-df', OLDER_OBJECT_CLIENT) spec_created = p4gf_util.ensure_spec( p4, "client", spec_id=client_name, values={'Host': None, 'Root': p4gf_dir, 'Description': 'Created by Perforce Git Fusion', 'View': view}) if not spec_created: p4gf_util.ensure_spec_values(p4, "client", client_name, {'Root': p4gf_dir, 'View': view})
def convert_client(args, p4, client_name): """Convert 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 old_client = p4.client p4.client = client_name print(" Processing 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):] client = p4.fetch_client() command_path = client["Root"] if not args.convert: print(" Removing client files for {}...".format(client_name)) print(" p4 sync -fqk {}/...#none".format(command_path)) print(" Create config for client {}...".format(client_name)) p4.client = old_client for group_template in group_list: group = group_template.format(view=view_name) print(" Leaving existing group {}".format(group)) print(" Remove client lock counter") print(" p4 counter -u -d {}".format(p4gf_lock.view_lock_name(view_name))) else: LOG_FILE.write("Processing client {}\n".format(client_name)) print(" Removing client files for {}...".format(client_name)) print(" p4 sync -fqk {}/...#none".format(command_path)) LOG_FILE.write("p4 sync -fqk {}/...#none\n".format(command_path)) p4.run('sync', '-fqk', command_path + '/...#none') print(" Creating config for client {}...".format(client_name)) LOG_FILE.write("Creating config for client {}...\n".format(client_name)) p4.client = old_client create_from_12x_gf_client_name(p4, client_name) for group_template in group_list: group = group_template.format(view=view_name) print(" Leaving existing group {}".format(group)) print(" Remove client lock counter") print(" p4 counter -u -d {}".format(p4gf_lock.view_lock_name(view_name))) LOG_FILE.write("p4 counter -u -d {}\n".format(p4gf_lock.view_lock_name(view_name))) _delete_counter(p4, p4gf_lock.view_lock_name(view_name))
def get_branch_dict(self): """Get a branch dictionary for this repo. If the p4gf_config exists, use that. Else if the p4 client exists create a branch dict containing a branch from the client views. Else return None """ LOG.debug("get_branch_dict for {0}".format(self.view_name)) # Repo config file already checked into Perforce? # Use that. config_path = p4gf_config.depot_path_repo(self.view_name) config_exists = p4gf_util.depot_file_exists(self.p4, config_path) if config_exists: self.config = p4gf_config.get_repo(self.p4, self.view_name) if self.config: return p4gf_branch.dict_from_config(self.config, self.p4) else: return None else: LOG.debug("checking if client {0} exists.".format(self.view_name)) if not p4gf_util.spec_exists(self.p4, 'client', self.view_name): LOG.debug(" client {0} NOT exists.".format( self.view_name)) return None view_lines = p4gf_util.first_value_for_key( self.p4.run('client', '-o', '-t', self.view_name, self.p4client), 'View') if not view_lines: return None else: # create a Branch object to manage this client view if isinstance(view_lines, str): view_lines = view_lines.splitlines() LOG.debug( "create branch from client views: {0}".format(view_lines)) branch = p4gf_branch.Branch() branch.branch_id = 'master' branch.git_branch_name = 'master' branch.view_p4map = P4.Map(view_lines) branch.view_lines = view_lines LOG.debug( "create branch from client branch view_p4map: {0}".format( branch.view_p4map)) LOG.debug( "create branch from client branch view_lines: {0}".format( branch.view_lines)) branch_dict = {} branch_dict[branch.branch_id] = branch return branch_dict
def get_branch_dict(self): """Get a branch dictionary for this repo. If the p4gf_config exists, use that. Else if the p4 client exists create a branch dict containing a branch from the client views. Else return None """ LOG.debug("get_branch_dict for {0}".format(self.view_name)) # Repo config file already checked into Perforce? # Use that. config_path = p4gf_config.depot_path_repo(self.view_name) config_exists = p4gf_util.depot_file_exists(self.p4, config_path) if config_exists: self.config = p4gf_config.get_repo(self.p4, self.view_name) if self.config: return p4gf_branch.dict_from_config(self.config, self.p4) else: return None else: LOG.debug("checking if client {0} exists.".format(self.view_name)) if not p4gf_util.spec_exists(self.p4, 'client', self.view_name): LOG.debug(" client {0} NOT exists.".format(self.view_name)) return None view_lines = p4gf_util.first_value_for_key( self.p4.run('client', '-o', '-t', self.view_name, self.p4client), 'View') if not view_lines: return None else: # create a Branch object to manage this client view if isinstance(view_lines, str): view_lines = view_lines.splitlines() LOG.debug("create branch from client views: {0}".format(view_lines)) branch = p4gf_branch.Branch() branch.branch_id = 'master' branch.git_branch_name = 'master' branch.view_p4map = P4.Map(view_lines) branch.view_lines = view_lines LOG.debug("create branch from client branch view_p4map: {0}". format(branch.view_p4map)) LOG.debug("create branch from client branch view_lines: {0}". format(branch.view_lines)) branch_dict = {} branch_dict[branch.branch_id] = branch return branch_dict
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_util.view_to_client_name(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() ctx.p4.run('sync', '-fq', command_path + '#none') ctx.p4.run('client', '-df', client_name) for vdir in [ctx.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 repo_from_template_client(p4, view_name, view_name_p4client, client_name, client_root, enable_mismatched_rhs): ''' Create a new Perforce client spec <client_name> using existing Perforce client spec <view_name> as a template (just use its View). ''' # view_name_p4client is the p4client # view_name is the gfinternal repo name # view_name differs from view_name_p4client if latter contains special chars # or was configured with --p4client argument if not p4gf_util.spec_exists(p4, 'client', view_name_p4client): return INIT_REPO_NOVIEW client = p4.run('client', '-o', view_name_p4client)[0] if 'Stream' in client: return _repo_from_stream(p4, view_name, client.get('Stream'), client_name, client_root, enable_mismatched_rhs) with Validator.from_template_client(view_name, p4, view_name_p4client) as validator: if not validator.is_valid(enable_mismatched_rhs): return INIT_REPO_CONFIG_FILE_BAD # Seed a new client using the view's view as a template. LOG.info( "Git Fusion client %s does not exist," " creating from existing Perforce client %s", client_name, view_name_p4client) view = p4gf_util.first_value_for_key( p4.run('client', '-o', '-t', view_name_p4client, client_name), 'View') create_repo_client(p4, view_name, client_name, client_root, view, None) return INIT_REPO_OK
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 _repo_from_stream(p4, view_name, stream_name, client_name, client_root, enable_mismatched_rhs, handle_imports=True): """Create a new client from the named stream. Create a new Perforce client spec <client_name> using existing Perforce stream spec <stream_name> as a template (just use its View). Returns one of the INIT_REPO_* constants. """ # stream_name is the name of a stream, e.g. '//depot/stream' # view_name is the gfinternal repo name if not p4gf_util.spec_exists(p4, 'stream', stream_name): return INIT_REPO_NOVIEW with Validator.from_stream(view_name, p4, stream_name) as validator: if not validator.is_valid(enable_mismatched_rhs): return INIT_REPO_CONFIG_FILE_BAD # Seed a new client using the stream's view as a template. LOG.info( "Git Fusion client %s does not exist, creating from existing Perforce stream %s", client_name, stream_name) # Create virtual stream with excluded paths, use that for client. stream = p4.fetch_stream(stream_name) if handle_imports: config = p4gf_config.get_repo(p4, view_name) imports_enabled = p4gf_config.is_feature_enabled( config, p4gf_config.FEATURE_IMPORTS) else: imports_enabled = False if imports_enabled: stream_paths = p4gf_streams.stream_import_exclude(stream['Paths']) else: stream_paths = stream['Paths'] desc = (_("Created by Perforce Git Fusion for work in '{view}'.").format( view=p4gf_translate.TranslateReponame.repo_to_git(view_name))) spec_values = { 'Owner': p4gf_const.P4GF_USER, 'Parent': stream_name, 'Type': 'virtual', 'Description': desc, 'Options': 'notoparent nofromparent', 'Paths': stream_paths, 'Remapped': ['.gitmodules-{} .gitmodules'.format(view_name)] } if imports_enabled: stream_name += '_p4gfv' p4gf_util.set_spec(p4, 'stream', spec_id=stream_name, values=spec_values) LOG.debug('virtual stream {} created for {}'.format( stream_name, client_name)) create_repo_client(p4, view_name, client_name, client_root, None, stream_name) return INIT_REPO_OK
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 _create_p4_client(p4, view_name, client_name, client_root, enable_mismatched_rhs, view_name_p4client, handle_imports=True): """Create the p4 client to contain Git meta-data mirror. Keyword arguments: p4 -- Perforce client API view_name -- client view of repository to clone - internal (translated) viewname client_name -- client that will be created client_root -- path for client workspace enable_mismatched_rhs -- allow branches to have differing RHS? view_name_p4client -- name of actual p4 client on which to base this new repo if None - will be determined from view_name if needed Returns one of the INIT_REPO_* constants. """ # Ensure the client root directory has been created. if not os.path.exists(client_root): os.makedirs(client_root) view_name_git = p4gf_translate.TranslateReponame.repo_to_git(view_name) LOG.debug("_create_p4_client(): view_name_git {0} view_name {1} view_name_p4client {2}". format(view_name_git, view_name ,view_name_p4client)) # If a Git Fusion client for this view already exists, use that, # no need to init the repo. # Do make sure that the client root is correct. if p4gf_util.spec_exists(p4, 'client', client_name): LOG.debug("%s client already exists for %s", client_name, view_name) p4gf_util.ensure_spec_values(p4, 'client', client_name , { 'Root' : client_root , 'Options' : CLIENT_OPTIONS }) return INIT_REPO_EXISTS # Repo config file already checked into Perforce? # Use that. config_path = p4gf_config.depot_path_repo(view_name) config_exists = p4gf_util.depot_file_exists(p4, config_path) if config_exists: return repo_from_config( p4, view_name, client_name, client_root , enable_mismatched_rhs) # Client exist with the same name as this Git Fusion repo? # Build a new config, check it into Perforce, and use that. if not view_name_p4client: view_name_p4client = p4gf_translate.TranslateReponame.git_to_p4client(view_name_git) nop4client = '' if p4gf_util.spec_exists(p4, 'client', view_name_p4client): return repo_from_template_client( p4, view_name, view_name_p4client, client_name , client_root , enable_mismatched_rhs) else: nop4client = _("p4 client '{0}' does not exist\n").format(view_name_p4client) # creating repo from stream? # note that we can't pass '//depot/stream' because git would be confused # but it's ok to pass 'depot/stream' and add the leading '//' here stream_name = '//'+view_name_git if p4gf_util.spec_exists(p4, 'stream', stream_name): return _repo_from_stream(p4, view_name, stream_name, client_name, client_root, enable_mismatched_rhs, handle_imports) # We don't have, and cannot create, a config for this repo. # Say so and give up. msg = p4gf_const.NO_REPO_MSG_TEMPLATE.format(view_name=view_name ,view_name_p4client=view_name_p4client ,nop4client=nop4client) LOG.warn(msg) _print_stderr(msg) return INIT_REPO_NOVIEW
def import_submodules(ctx, view, change_view, import_paths): """For stream clients, create a submodule for each import. Arguments: ctx -- parent repo context. view -- the parent stream's 'View'. change_view -- the parent stream's 'ChangeView'. import_paths -- result from p4gf_streams.match_import_paths() on the virtual stream's paths and the parent stream's paths. """ usermap = p4gf_usermap.UserMap(ctx.p4gf) user_3tuple = usermap.lookup_by_p4user(p4gf_const.P4GF_USER) if not user_3tuple: LOG.error('Missing Perforce user {}'.format(p4gf_const.P4GF_USER)) return client_name = ctx.config.p4client LOG.debug('processing imports for {}'.format(client_name)) LOG.debug3('import_submodules() view={}, change_view={}, import_paths={}'.format( view, change_view, import_paths)) change_views = p4gf_streams.stream_imports_with_changes(view, change_view, import_paths) LOG.debug2('import_submodules() change_views={}'.format(change_views)) if not change_views and LOG.isEnabledFor(logging.DEBUG2): LOG.debug2('import_submodules() view={} change_view={} import_paths={}'.format( view, change_view, import_paths)) # initialize and populate the submodules old_sha1 = ctx.view_repo.lookup_reference('HEAD').resolve().hex for depot_path, change_num, local_path in change_views: # avoid double-nesting by excluding the local path from the client path client_path = "//{}/...".format(client_name) LOG.debug('import_submodules() for {} => {}'.format(depot_path, client_path)) stream_name = depot_path[:-4] if p4gf_util.spec_exists(ctx.p4, 'stream', stream_name): # convert stream name to repo name by pruning leading slashes repo_name = p4gf_streams.repo_name_from_depot_path(stream_name) config = None LOG.debug('initializing stream import for {}'.format(depot_path)) else: # create a repo configuration file for this 1-line view repo_name = p4gf_streams.repo_name_from_depot_path(depot_path) client_less_path = CLIENT_LESS_REGEX.match(client_path).group(1) if client_path and client_path[0] == '"': client_less_path = '"' + client_less_path repo_view = depot_path + " " + client_less_path LOG.debug('creating config for {}'.format(repo_name)) config = p4gf_config.default_config_repo_for_view_plain(ctx.p4, repo_name, repo_view) # prepare to initialize the repository p4 = p4gf_create_p4.create_p4() if not p4: LOG.error('unable to create P4 instance for {}'.format(repo_name)) return with p4gf_lock.view_lock(p4, repo_name) as view_lock: if config: p4gf_config.create_file_repo_from_config(ctx, repo_name, config) LOG.debug('initializing repo for {}'.format(repo_name)) result = init_repo(p4, repo_name, view_lock, handle_imports=False) if result > INIT_REPO_OK: return result with p4gf_context.create_context(repo_name, view_lock) as subtxt: # set up gitmirror for child repos p4gf_gitmirror.setup_spawn(repo_name) # populate the submodule shared_in_progress = p4gf_lock.shared_host_view_lock_exists(subtxt.p4, repo_name) if not shared_in_progress: copy_submodule(ctx, repo_name, subtxt, local_path, change_num, user_3tuple) p4gf_create_p4.p4_disconnect(p4) # Remove any submodules controlled by Git Fusion that no longer match # any of the current import paths. deport_submodules(ctx, import_paths, user_3tuple) # # Ensure the Git commits we just created are copied back to Perforce by # faking a 'push' from the client. Roll the HEAD reference ('master') # back to the old SHA1, assign the commits to Perforce branches, then # move the reference back to the latest commit and copy everything to # the depot as usual. # new_head = ctx.view_repo.lookup_reference('HEAD').resolve() ctx.view_repo.git_reference_create(new_head.name, old_sha1, True) prt = p4gf_branch_id.PreReceiveTuple(old_sha1, new_head.hex, new_head.name) LOG.debug('Copying modules to depot: {}'.format(prt)) assigner = p4gf_branch_id.Assigner(ctx.branch_dict(), [prt], ctx) assigner.assign() ctx.view_repo.git_reference_create(new_head.name, new_head.hex, True) err = p4gf_copy_to_p4.copy_git_changes_to_p4(ctx, prt, assigner, None) if err: LOG.error(err)
def import_submodules(ctx, view, change_view, import_paths): """For stream clients, create a submodule for each import. Arguments: ctx -- parent repo context. view -- the parent stream's 'View'. change_view -- the parent stream's 'ChangeView'. import_paths -- result from p4gf_streams.match_import_paths() on the virtual stream's paths and the parent stream's paths. """ usermap = p4gf_usermap.UserMap(ctx.p4gf) user_3tuple = usermap.lookup_by_p4user(p4gf_const.P4GF_USER) if not user_3tuple: LOG.error('Missing Perforce user {}'.format(p4gf_const.P4GF_USER)) return client_name = ctx.config.p4client LOG.debug('processing imports for {}'.format(client_name)) LOG.debug3( 'import_submodules() view={}, change_view={}, import_paths={}'.format( view, change_view, import_paths)) change_views = p4gf_streams.stream_imports_with_changes( view, change_view, import_paths) LOG.debug2('import_submodules() change_views={}'.format(change_views)) if not change_views and LOG.isEnabledFor(logging.DEBUG2): LOG.debug2( 'import_submodules() view={} change_view={} import_paths={}'. format(view, change_view, import_paths)) # initialize and populate the submodules old_sha1 = ctx.view_repo.lookup_reference('HEAD').resolve().hex for depot_path, change_num, local_path in change_views: # avoid double-nesting by excluding the local path from the client path client_path = "//{}/...".format(client_name) LOG.debug('import_submodules() for {} => {}'.format( depot_path, client_path)) stream_name = depot_path[:-4] if p4gf_util.spec_exists(ctx.p4, 'stream', stream_name): # convert stream name to repo name by pruning leading slashes repo_name = p4gf_streams.repo_name_from_depot_path(stream_name) config = None LOG.debug('initializing stream import for {}'.format(depot_path)) else: # create a repo configuration file for this 1-line view repo_name = p4gf_streams.repo_name_from_depot_path(depot_path) client_less_path = CLIENT_LESS_REGEX.match(client_path).group(1) if client_path and client_path[0] == '"': client_less_path = '"' + client_less_path repo_view = depot_path + " " + client_less_path LOG.debug('creating config for {}'.format(repo_name)) config = p4gf_config.default_config_repo_for_view_plain( ctx.p4, repo_name, repo_view) # prepare to initialize the repository p4 = p4gf_create_p4.create_p4() if not p4: LOG.error('unable to create P4 instance for {}'.format(repo_name)) return with p4gf_lock.view_lock(p4, repo_name) as view_lock: if config: p4gf_config.create_file_repo_from_config( ctx, repo_name, config) LOG.debug('initializing repo for {}'.format(repo_name)) result = init_repo(p4, repo_name, view_lock, handle_imports=False) if result > INIT_REPO_OK: return result with p4gf_context.create_context(repo_name, view_lock) as subtxt: # set up gitmirror for child repos p4gf_gitmirror.setup_spawn(repo_name) # populate the submodule shared_in_progress = p4gf_lock.shared_host_view_lock_exists( subtxt.p4, repo_name) if not shared_in_progress: copy_submodule(ctx, repo_name, subtxt, local_path, change_num, user_3tuple) p4gf_create_p4.p4_disconnect(p4) # Remove any submodules controlled by Git Fusion that no longer match # any of the current import paths. deport_submodules(ctx, import_paths, user_3tuple) # # Ensure the Git commits we just created are copied back to Perforce by # faking a 'push' from the client. Roll the HEAD reference ('master') # back to the old SHA1, assign the commits to Perforce branches, then # move the reference back to the latest commit and copy everything to # the depot as usual. # new_head = ctx.view_repo.lookup_reference('HEAD').resolve() ctx.view_repo.git_reference_create(new_head.name, old_sha1, True) prt = p4gf_branch_id.PreReceiveTuple(old_sha1, new_head.hex, new_head.name) LOG.debug('Copying modules to depot: {}'.format(prt)) assigner = p4gf_branch_id.Assigner(ctx.branch_dict(), [prt], ctx) assigner.assign() ctx.view_repo.git_reference_create(new_head.name, new_head.hex, True) err = p4gf_copy_to_p4.copy_git_changes_to_p4(ctx, prt, assigner, None) if err: LOG.error(err)
def _global_init(p4): """Check that p4gf_super_init has been run and created the following * user git-fusion-user * depot //P4GF_DEPOT * group git-fusion-pull * group git-fusion-push * protects entries """ # # The global initialization process below must be idempotent in the sense # that it is safe to perform more than once. As such, there are checks to # determine if work is needed or not, and if that work results in an # error, log and carry on with the rest of the steps, with the assumption # that a previous attempt had failed in the middle (or possibly that # another instance of Git Fusion has started at nearly the same time as # this one). # p4gf_util.has_server_id_or_exit() spec_list = { 'user1': p4gf_const.P4GF_USER, 'user2': p4gf_util.gf_reviews_user_name(), 'user3': p4gf_const.P4GF_REVIEWS__NON_GF, 'group': p4gf_const.P4GF_GROUP, 'depot': p4gf_const.P4GF_DEPOT } for spec_type, spec_id in spec_list.items(): spec_type = re.sub(NTR(r'\d$'), '', spec_type) if not p4gf_util.spec_exists(p4, spec_type, spec_id): # pylint:disable=C0301 raise RuntimeError(_("error: {spec_type} '{spec_id}' does not exist." " Please contact your administrator.") .format(spec_type=spec_type, spec_id=spec_id)) # pylint:enable=C0301 for group in [p4gf_group.PERM_PULL, p4gf_group.PERM_PUSH]: c = p4gf_group.create_global_perm(p4, group) if c: _info(_("Global permission group '{}' created.").format(group)) else: _info(_("Global permission group '{}' already exists.").format(group)) c = p4gf_group.create_default_perm(p4) if c: _info(_("Default permission counter '{}' set to '{}'.") .format( p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT , p4gf_group.DEFAULT_PERM )) else: _info(_("Default permission counter '{}' already exists.") .format(p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT)) # Require that single git-fusion-user have admin privileges # over the //P4GF_DEPOT/ depot is_protects_empty = False try: p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m', '//{depot}/...'.format(depot=p4gf_const.P4GF_DEPOT)) except P4.P4Exception: # Why MsgDm_ReferClient here? Because p4d 11.1 returns # "must refer to client" instead of # "Protections table is empty" when given a depot path to # 'p4 protects -m -u'. Surprise! if p4gf_p4msg.find_all_msgid(p4, [ p4gf_p4msgid.MsgDm_ProtectsEmpty , p4gf_p4msgid.MsgDm_ReferClient ]): is_protects_empty = True # All other errors are fatal, propagated. if is_protects_empty: # - order the lines in increasing permission # - end with at least one user (even a not-yet-created user) with super # write user * * //... # admin user git-fusion-user * //... # super user super * //... p4gf_util.set_spec(p4, 'protect', values={ 'Protections': ["super user * * //...", "super user {user} * //...".format(user=p4gf_const.P4GF_USER), "admin user {user} * //{depot}/..." .format(user=p4gf_const.P4GF_USER, depot=p4gf_const.P4GF_DEPOT)]}) _info(_('Protects table set.'))
def _create_p4_client(p4, view_name, client_name, client_root, enable_mismatched_rhs, view_name_p4client, handle_imports=True): """Create the p4 client to contain Git meta-data mirror. Keyword arguments: p4 -- Perforce client API view_name -- client view of repository to clone - internal (translated) viewname client_name -- client that will be created client_root -- path for client workspace enable_mismatched_rhs -- allow branches to have differing RHS? view_name_p4client -- name of actual p4 client on which to base this new repo if None - will be determined from view_name if needed Returns one of the INIT_REPO_* constants. """ # Ensure the client root directory has been created. if not os.path.exists(client_root): os.makedirs(client_root) view_name_git = p4gf_translate.TranslateReponame.repo_to_git(view_name) LOG.debug( "_create_p4_client(): view_name_git {0} view_name {1} view_name_p4client {2}" .format(view_name_git, view_name, view_name_p4client)) # If a Git Fusion client for this view already exists, use that, # no need to init the repo. # Do make sure that the client root is correct. if p4gf_util.spec_exists(p4, 'client', client_name): LOG.debug("%s client already exists for %s", client_name, view_name) p4gf_util.ensure_spec_values(p4, 'client', client_name, { 'Root': client_root, 'Options': CLIENT_OPTIONS }) return INIT_REPO_EXISTS # Repo config file already checked into Perforce? # Use that. config_path = p4gf_config.depot_path_repo(view_name) config_exists = p4gf_util.depot_file_exists(p4, config_path) if config_exists: return repo_from_config(p4, view_name, client_name, client_root, enable_mismatched_rhs) # Client exist with the same name as this Git Fusion repo? # Build a new config, check it into Perforce, and use that. if not view_name_p4client: view_name_p4client = p4gf_translate.TranslateReponame.git_to_p4client( view_name_git) nop4client = '' if p4gf_util.spec_exists(p4, 'client', view_name_p4client): return repo_from_template_client(p4, view_name, view_name_p4client, client_name, client_root, enable_mismatched_rhs) else: nop4client = _("p4 client '{0}' does not exist\n").format( view_name_p4client) # creating repo from stream? # note that we can't pass '//depot/stream' because git would be confused # but it's ok to pass 'depot/stream' and add the leading '//' here stream_name = '//' + view_name_git if p4gf_util.spec_exists(p4, 'stream', stream_name): return _repo_from_stream(p4, view_name, stream_name, client_name, client_root, enable_mismatched_rhs, handle_imports) # We don't have, and cannot create, a config for this repo. # Say so and give up. msg = p4gf_const.NO_REPO_MSG_TEMPLATE.format( view_name=view_name, view_name_p4client=view_name_p4client, nop4client=nop4client) LOG.warn(msg) _print_stderr(msg) return INIT_REPO_NOVIEW
def _global_init(p4): """Check that p4gf_super_init has been run and created the following * user git-fusion-user * depot //P4GF_DEPOT * group git-fusion-pull * group git-fusion-push * protects entries """ # # The global initialization process below must be idempotent in the sense # that it is safe to perform more than once. As such, there are checks to # determine if work is needed or not, and if that work results in an # error, log and carry on with the rest of the steps, with the assumption # that a previous attempt had failed in the middle (or possibly that # another instance of Git Fusion has started at nearly the same time as # this one). # p4gf_util.has_server_id_or_exit() spec_list = { 'user1': p4gf_const.P4GF_USER, 'user2': p4gf_util.gf_reviews_user_name(), 'user3': p4gf_const.P4GF_REVIEWS__NON_GF, 'group': p4gf_const.P4GF_GROUP, 'depot': p4gf_const.P4GF_DEPOT } for spec_type, spec_id in spec_list.items(): spec_type = re.sub(NTR(r'\d$'), '', spec_type) if not p4gf_util.spec_exists(p4, spec_type, spec_id): # pylint:disable=C0301 raise RuntimeError( _("error: {spec_type} '{spec_id}' does not exist." " Please contact your administrator.").format( spec_type=spec_type, spec_id=spec_id)) # pylint:enable=C0301 for group in [p4gf_group.PERM_PULL, p4gf_group.PERM_PUSH]: c = p4gf_group.create_global_perm(p4, group) if c: _info(_("Global permission group '{}' created.").format(group)) else: _info( _("Global permission group '{}' already exists.").format( group)) c = p4gf_group.create_default_perm(p4) if c: _info( _("Default permission counter '{}' set to '{}'.").format( p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT, p4gf_group.DEFAULT_PERM)) else: _info( _("Default permission counter '{}' already exists.").format( p4gf_const.P4GF_COUNTER_PERMISSION_GROUP_DEFAULT)) # Require that single git-fusion-user have admin privileges # over the //P4GF_DEPOT/ depot is_protects_empty = False try: p4.run('protects', '-u', p4gf_const.P4GF_USER, '-m', '//{depot}/...'.format(depot=p4gf_const.P4GF_DEPOT)) except P4.P4Exception: # Why MsgDm_ReferClient here? Because p4d 11.1 returns # "must refer to client" instead of # "Protections table is empty" when given a depot path to # 'p4 protects -m -u'. Surprise! if p4gf_p4msg.find_all_msgid( p4, [p4gf_p4msgid.MsgDm_ProtectsEmpty, p4gf_p4msgid.MsgDm_ReferClient ]): is_protects_empty = True # All other errors are fatal, propagated. if is_protects_empty: # - order the lines in increasing permission # - end with at least one user (even a not-yet-created user) with super # write user * * //... # admin user git-fusion-user * //... # super user super * //... p4gf_util.set_spec(p4, 'protect', values={ 'Protections': [ "super user * * //...", "super user {user} * //...".format( user=p4gf_const.P4GF_USER), "admin user {user} * //{depot}/...".format( user=p4gf_const.P4GF_USER, depot=p4gf_const.P4GF_DEPOT) ] }) _info(_('Protects table set.'))
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()