def main(): """Parse the command-line arguments and report on locks.""" desc = _(DESCRIPTION) parser = p4gf_util.create_arg_parser(desc=desc) parser.add_argument( NTR('--config'), metavar=NTR('config'), help=_('Path to Git Fusion p4gf_config file (required)'), required=True) parser.add_argument('-u', '--p4user', metavar='p4user', help=_('Perforce user')) parser.add_argument('-p', '--p4port', metavar='p4port', help=_('Perforce server')) parser.add_argument('--locale', metavar='locale', default='en_US.UTF-8', help=_('system locale setting')) args = parser.parse_args() need_serverid = False try: p4gf_util.get_server_id() except: # pylint: disable=W0702 need_serverid = True # If connect args not passed, check that the environment is set. if not args.p4port: if 'P4PORT' not in os.environ and 'P4GF_ENV' not in os.environ: print( _("Neither --p4port is an argument nor are P4GF_ENV and P4PORT in the environment." )) sys.exit(0) if 'P4PORT' in os.environ: args.p4port = os.environ['P4PORT'] else: # Set the requested port for Git Fusion's environment os.environ['P4PORT'] = args.p4port if not args.p4user: if 'P4USER' not in os.environ: print( _("Neither --p4user is an argument nor is P4USER in the environment." )) sys.exit(0) else: args.p4user = os.environ['P4USER'] else: # Set the requested user for Git Fusion's environment os.environ['P4USER'] = args.p4user repo_size = RepoSize(args.config, args.p4port, args.p4user, args.locale, need_serverid) repo_size.estimate_size() repo_size.report()
def create_p4_temp_client(port=None, user=None, skip_count=False): """Create a connected P4 instance with a generic temporary client. Dropping the connection will automatically delete the client. This is useful for owning the locks and permitting reliable lock stealing by other processes. :return: P4API instance. """ p4 = create_p4(port, user, warn_no_client=False) if p4 is None: # Propagate the error (that has already been reported). return None name = p4gf_const.P4GF_OBJECT_CLIENT_UNIQUE.format( server_id=p4gf_util.get_server_id(), uuid=str(uuid.uuid1())) client = p4.fetch_client(name) client['Owner'] = p4gf_const.P4GF_USER client['LineEnd'] = NTR('unix') client['View'] = [ '//{0}/... //{1}/...'.format(p4gf_const.P4GF_DEPOT, name) ] # 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 client['Options'] = p4gf_const.CLIENT_OPTIONS.replace("normdir", "rmdir") client['Root'] = p4gf_const.P4GF_HOME # The -x option is a deep undoc feature that signals to p4d that this # is a temporary client, which will be automatically deleted upon # disconnect. Requires passing the client specification using -i flag. # N.B. this client cannot shelve changes. See @465851 for details. # N.B. only one temporary client per connection will be auto-deleted p4.client = name p4.save_client(client, '-x') LOG.debug("create_p4_temp_client() created temp client %s", name) if 'P4T4TEST_ORIG_LANG' in os.environ and not skip_count: # In the testing environment, we check that each process created no # more than one temporary client (concurrently). Keep the highest # value, rather than whatever the last count happened to be. prefix = p4gf_const.P4GF_OBJECT_CLIENT_UNIQUE.format( server_id=p4gf_util.get_server_id(), uuid='') count = _count_active(prefix) # Some tests set up an unnatural environment, so don't let those # blow up in unexpected ways (i.e. fail gracefully elsewhere). with p4.at_exception_level(P4.P4.RAISE_NONE): value = p4gf_p4key.get( p4, "git-fusion-temp-clients-{}".format(os.getpid())) if int(value) < count: p4gf_p4key.set( p4, "git-fusion-temp-clients-{}".format(os.getpid()), str(count)) return p4
def _last_copied_tag_counter_name(ctx): ''' Return the name of a counter that holds the latest tag changelist number for this Git Fusion server. ''' return _calc_last_copied_tag_counter_name(ctx.config.view_name, p4gf_util.get_server_id())
def heartbeat_content(self): ''' What should we write to our heartbeat counter? Enough data that an admin could figure out who's hogging the lock. If enough time has elapsed since the last call to this function, updates the content string. Returns a tuple containing the current and previous content strings. ''' now = time.time() if self.__heartbeat_time and now - self.__heartbeat_time < HEART_RATE: return self.__heartbeat_content, self.__heartbeat_content self.__heartbeat_time = now # Produce a heartbeat value that is unique for each host and # process, and changes each time it is updated. Values are not so # important, but the value must continue to change so that others # can determine if the lock holder has died. val = NTR('{host} -- {process} -- {time}') \ .format( host = p4gf_util.get_server_id() , process = os.getpid() , time = int(self.__heartbeat_time) ) last = self.__heartbeat_content self.__heartbeat_content = val return self.__heartbeat_content, last
def shared_host_view_lock_exists(p4, view_name): ''' Are one or more processes already cloning through this repo? ''' host_name = p4gf_util.get_server_id() result = get_shared_host_view_lock_state(p4, host_name, view_name) return result == SHARED
def last_copied_change_counter_name(self): ''' Return a counter that holds the highest changelist number copied to the our repo, on our Git Fusion server. ''' return calc_last_copied_change_counter_name(self.config.view_name, p4gf_util.get_server_id())
def last_copied_change_counter_name(self): ''' Return a counter that holds the highest changelist number copied to the our repo, on our Git Fusion server. ''' return calc_last_copied_change_counter_name( self.config.view_name , p4gf_util.get_server_id())
def _generate_client_name(self): ''' Return "git-fusion-{server_id}-{repo_name}-temp-{n}", suitable for use as a name for a temporary client ''' return p4gf_const.P4GF_REPO_TEMP_CLIENT.format( server_id=p4gf_util.get_server_id(), repo_name=self.ctx.config.view_name, n=len(self.q.q))
def shared_host_view_lock(p4, view_name , first_acquire_func=None , last_release_func=None): '''Return a shared lock for the desired view, specific to the current host. ''' host_name = p4gf_util.get_server_id() return SharedViewLock(p4, host_name, view_name , first_acquire_func=first_acquire_func , last_release_func=last_release_func)
def _get_counter_name(): """Generate the name of the counter for keeping track of the last change that this server has retrieved for the user keys. """ global CounterName if not CounterName: host = p4gf_util.get_server_id() CounterName = p4gf_const.P4GF_COUNTER_UPDATE_AUTH_KEYS.format(host) return CounterName
def _get_p4key_name(): """Generate the name of the p4key for keeping track of the last change that this server has retrieved for the user keys. """ global P4KeyName if not P4KeyName: host = p4gf_util.get_server_id() P4KeyName = p4gf_const.P4GF_P4KEY_UPDATE_AUTH_KEYS.format(host) return P4KeyName
def init(p4): """Ensure both global and host-specific initialization are completed. """ started_counter = p4gf_const.P4GF_COUNTER_INIT_STARTED complete_counter = p4gf_const.P4GF_COUNTER_INIT_COMPLETE if not old_counter_present(p4): Verbosity.report(Verbosity.DEBUG, _('Old 2012.2 counter not present.')) if not _maybe_perform_init(p4, started_counter, complete_counter, _global_init): Verbosity.report(Verbosity.INFO, _('Permissions already initialized. Not changing.')) server_id = p4gf_util.get_server_id() started_counter = p4gf_const.P4GF_COUNTER_INIT_STARTED + '-' + server_id complete_counter = p4gf_const.P4GF_COUNTER_INIT_COMPLETE + '-' + server_id p4gf_dir = p4gf_const.P4GF_HOME client_name = p4gf_util.get_object_client_name() def client_init(p4): '''Perform host-specific initialization (and create sample usermap).''' # Set up the host-specific client. _create_client(p4, client_name, p4gf_dir) # Ensure the default user map and global config files are in place. _write_user_map(p4, client_name, p4gf_dir) p4gf_config.create_file_global(p4) _delete_old_init_counters(p4, server_id) if not _maybe_perform_init(p4, started_counter, complete_counter, client_init): Verbosity.report( Verbosity.INFO, _('Client and usermap already initialized. Not changing.')) # If client already created, make sure it hasn't been tweaked. ###: do we really need to handle this case? this is here just to pass the tests view = [ '//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=client_name) ] p4gf_util.ensure_spec_values(p4, 'client', client_name, { 'Root': p4gf_dir, 'View': view }) # Perform any necessary upgrades within a "lock" to avoid race conditions. # For now, the lock is global, but could conceivably loosen to host-only. started_counter = p4gf_const.P4GF_COUNTER_UPGRADE_STARTED complete_counter = p4gf_const.P4GF_COUNTER_UPGRADE_COMPLETE if not _maybe_perform_init(p4, started_counter, complete_counter, _upgrade_p4gf): Verbosity.report( Verbosity.INFO, _('Global config file already initialized. Not changing.')) # Require non-empty Git config user.name and user.email. _ensure_git_config_non_empty('user.name', _('Git Fusion Machinery')) _ensure_git_config_non_empty('user.email', _('*****@*****.**'))
def __init__(self, p4, blocking=True): """Init lock, setting lock key name used for reviews.""" super(ReviewsLock, self).__init__( p4=p4, lock_key=p4gf_const.P4GF_REVIEWS_COMMON_LOCK, blocking=blocking) self.content = { 'server_id': p4gf_util.get_server_id(), 'process_id': os.getpid(), 'start_time': _process_start_time() }
def _remove_local_root(localroot): """ Remove the contents of the P4GF local workspace, disregarding whether the root is a symbolic link. Save and re-write the server-id file after removing contents. """ LOG.debug2("_remove_local_root(): {}".format(localroot)) # get the server_id server_id = p4gf_util.get_server_id() _remove_tree(localroot) # re-write server_id p4gf_util.write_server_id_to_file(server_id)
def init(p4): """Ensure both global and host-specific initialization are completed.""" _check_for_old_p4key(p4) started_p4key = p4gf_const.P4GF_P4KEY_INIT_STARTED complete_p4key = p4gf_const.P4GF_P4KEY_INIT_COMPLETE _init_if_needed(p4, started_p4key, complete_p4key, _global_init, _('Permissions already initialized. Not changing.')) server_id = p4gf_util.get_server_id() started_p4key = p4gf_const.P4GF_P4KEY_INIT_STARTED + '-' + server_id complete_p4key = p4gf_const.P4GF_P4KEY_INIT_COMPLETE + '-' + server_id p4gf_dir = p4gf_const.P4GF_HOME def client_init(p4): """Perform host-specific initialization (and create sample usermap).""" # Set up the host-specific client. _create_client(p4) # Ensure the default user map and global config files are in place. _create_user_map(p4, p4.client, p4gf_dir) p4gf_config.GlobalConfig.init(p4) with p4.at_exception_level(p4.RAISE_ERROR): p4gf_config.GlobalConfig.write_if(p4) _delete_old_init_p4keys(p4, server_id) if not _init_if_needed(p4, started_p4key, complete_p4key, client_init, _('Client and usermap already initialized. Not changing.')): # If client already created, make sure it hasn't been tweaked. # ##: do we really need to handle this case? this is here just to pass the tests view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=p4.client)] p4gf_p4spec.ensure_spec_values(p4, 'client', p4.client, {'Root': p4gf_dir, 'View': view}) # Perform any necessary upgrades within a "lock" to avoid race conditions. # For now, the lock is global, but could conceivably loosen to host-only. started_p4key = p4gf_const.P4GF_P4KEY_UPGRADE_STARTED complete_p4key = p4gf_const.P4GF_P4KEY_UPGRADE_COMPLETE _init_if_needed(p4, started_p4key, complete_p4key, _upgrade_p4gf, _('Global config file already initialized. Not changing.')) # Require non-empty Git config user.name and user.email. _ensure_git_config_non_empty('user.name', _('Git Fusion Machinery')) _ensure_git_config_non_empty('user.email', _('*****@*****.**')) # Turn on CVE-CVE-2014-9390 rejection added in Git 2.2.1. # This linux server isn't vulnerable, but we still don't want to host # offending repos that could hit Windows/Mac OS X workstations. _ensure_git_config_non_empty('receive.fsckObjects', True) _ensure_git_config_non_empty('core.protectHFS', True) _ensure_git_config_non_empty('core.protectNTFS', True)
def __init__(self, p4, repo_name, blocking=True, group_id=None): """Initialize the lock.""" super(RepoLock, self).__init__(p4, blocking) self.lock_key = p4gf_const.P4GF_P4KEY_LOCK_VIEW.format(repo_name=repo_name) self.owners_key = p4gf_const.P4GF_P4KEY_LOCK_VIEW_OWNERS.format(repo_name=repo_name) self.lock = SimpleLock(p4, self.lock_key, blocking=blocking) self.group_id = group_id or str(os.getpid()) self.server_id = p4gf_util.get_server_id() self.process_id = os.getpid() self.start_time = _process_start_time() self.ignore_pending_acquire = False self._post_lock_release_cb = None self._transfer_complete_cb = None self._acquire_time = None self._repo_name = repo_name
def unlock_delete_temp_clients(self): """Unlock the temp clients so the user may consequently delete them.""" pattern = p4gf_const.P4GF_REPO_TEMP_CLIENT.format( server_id=p4gf_util.get_server_id(), repo_name=self.ctx.config.repo_name, uuid='*') clients = [ client['client'] for client in self.ctx.p4gfrun('clients', '-e', pattern) ] options = re.sub('locked', 'unlocked', p4gf_const.CLIENT_OPTIONS) for client in clients: p4gf_p4spec.ensure_spec_values(self.ctx.p4gf, spec_type='client', spec_id=client, values={'Options': options}) self.ctx.p4gfrun('client', '-d', client)
def cleanup_all(self): """Find and delete all temporary clients for the associated repo. Assumes the caller has the lock on the repository. """ LOG.debug2("cleanup_all() removing all temp clients...") pattern = p4gf_const.P4GF_REPO_TEMP_CLIENT.format( server_id=p4gf_util.get_server_id(), repo_name=self.ctx.config.repo_name, uuid='*') clients = self.ctx.p4gfrun('clients', '-e', pattern) for client in clients: client_name = client['client'] self.ctx.p4gfrun('client', '-d', '-f', client_name) LOG.debug("removing temp client {0}".format(client_name)) LOG.debug2("cleanup_all() removed %s temp clients", len(clients))
def overwrite_last_copied_tag(p4, repo_name, change_num): """Set the changelist number for the most recent tags change. :type p4: :class:`P4API` :param p4: P4 API instance :type repo_name: str :param repo_name: name fo the Git Fusion repository :type change_num: int || str :param change_num: changelist number to assign to tags key. """ keyname = _calc_last_copied_tag_p4key_name(repo_name, p4gf_util.get_server_id()) LOG.debug('overwrite_last_copied_tag() assigning {} to {}'.format( change_num, keyname)) return P4Key.set(p4, keyname, change_num)
def init(p4): """Ensure both global and host-specific initialization are completed. """ started_counter = p4gf_const.P4GF_COUNTER_INIT_STARTED complete_counter = p4gf_const.P4GF_COUNTER_INIT_COMPLETE if not old_counter_present(p4): Verbosity.report(Verbosity.DEBUG, _('Old 2012.2 counter not present.')) if not _maybe_perform_init(p4, started_counter, complete_counter, _global_init): Verbosity.report(Verbosity.INFO, _('Permissions already initialized. Not changing.')) server_id = p4gf_util.get_server_id() started_counter = p4gf_const.P4GF_COUNTER_INIT_STARTED + '-' + server_id complete_counter = p4gf_const.P4GF_COUNTER_INIT_COMPLETE + '-' + server_id p4gf_dir = p4gf_const.P4GF_HOME client_name = p4gf_util.get_object_client_name() def client_init(p4): '''Perform host-specific initialization (and create sample usermap).''' # Set up the host-specific client. _create_client(p4, client_name, p4gf_dir) # Ensure the default user map and global config files are in place. _write_user_map(p4, client_name, p4gf_dir) p4gf_config.create_file_global(p4) _delete_old_init_counters(p4, server_id) if not _maybe_perform_init(p4, started_counter, complete_counter, client_init): Verbosity.report(Verbosity.INFO, _('Client and usermap already initialized. Not changing.')) # If client already created, make sure it hasn't been tweaked. ###: do we really need to handle this case? this is here just to pass the tests view = ['//{depot}/... //{client}/...'.format(depot=p4gf_const.P4GF_DEPOT, client=client_name)] p4gf_util.ensure_spec_values(p4, 'client', client_name, {'Root': p4gf_dir, 'View': view}) # Perform any necessary upgrades within a "lock" to avoid race conditions. # For now, the lock is global, but could conceivably loosen to host-only. started_counter = p4gf_const.P4GF_COUNTER_UPGRADE_STARTED complete_counter = p4gf_const.P4GF_COUNTER_UPGRADE_COMPLETE if not _maybe_perform_init(p4, started_counter, complete_counter, _upgrade_p4gf): Verbosity.report(Verbosity.INFO, _('Global config file already initialized. Not changing.')) # Require non-empty Git config user.name and user.email. _ensure_git_config_non_empty('user.name', _('Git Fusion Machinery')) _ensure_git_config_non_empty('user.email', _('*****@*****.**'))
def cleanup(self): ''' Delete any temp client specs created on this server for this repo. Don't limit this to clients created by this pool instance. ''' pattern = p4gf_const.P4GF_REPO_TEMP_CLIENT.format( server_id=p4gf_util.get_server_id(), repo_name=self.ctx.config.view_name, n='*') clients = [ client['client'] for client in self.ctx.p4gfrun(NTR(["clients", "-e", pattern])) ] for client in clients: self.ctx.p4gfrun(NTR(["client", "-d", client])) # also clear this instance of references to deleted clients self.q.clear() self.view_lines_to_client_name.clear()
def _create_client_name_root_desc(self): """Return a tuple of (temp client name, root dir, description). Used to create temp clients. Name is of the form: "git-fusion-{server_id}-{repo_name}-temp-{uuid}". Ensure root dir exists. """ desc = (_("Created by Perforce Git Fusion for queries in '{view}'."). format(view=self.ctx.config.repo_name)) n = len(self.clients) + 1 # There is a slight chance we could collide here with other # processes operating within the same root directory. But, as long # as that work is happening within the p4key lock, we should be # okay. We are mostly concerned with having unique client names. client_root = "{}-temp-{}/".format(self.ctx.repo_dirs.p4root, n) if not os.path.exists(client_root): os.makedirs(client_root) client_name = p4gf_const.P4GF_REPO_TEMP_CLIENT.format( server_id=p4gf_util.get_server_id(), repo_name=self.ctx.config.repo_name, uuid=uuid.uuid1()) return (client_name, client_root, desc)
def remove_old_temp_and_repo_clients(p4): """Remove the old style temp clients and repo clients.""" server_id = p4gf_util.get_server_id() # Get a list of old style temp repo clients which may still exist. template = "git-fusion-{server_id}-{repo_name}-temp-{n}" pattern = template.format( server_id=server_id, repo_name='*', n='*') clients = [client['client'] for client in p4.run(NTR(["clients", "-e", pattern]))] for client in clients: try: p4.run(NTR(["client", "-d", "-f", client])) print(_("removed temp client {client}").format(client=client)) except P4.P4Exception: print(_("cannot remove temp client {client}").format(client=client)) # Get a list of old style permanent repo clients. old_client_repo_re = "git-fusion-{0}-[^-]+$".format(server_id) old_client_repo_re = re.compile(old_client_repo_re) pattern = p4gf_const.P4GF_REPO_CLIENT.format( server_id=server_id, repo_name='*') clients = [] for client in [client['client'] for client in p4.run(NTR(["clients", "-e", pattern]))]: if old_client_repo_re.match(client): clients.append(client) for client in clients: try: p4.run(NTR(["client", "-d", "-f", client])) print(_("removed temp client {client}").format(client=client)) except P4.P4Exception: print(_("cannot remove temp client {client}").format(client=client))
def _set_server_repo_config_rev(self, value): """Get the config file rev for the repo from the p4key.""" assert value is not None key = p4gf_const.P4GF_P4KEY_REPO_SERVER_CONFIG_REV.format( repo_name=self.repo_name, server_id=p4gf_util.get_server_id()) p4gf_util.set_p4key(self.p4, key, value)
def _last_copied_tag_p4key_name(ctx): """Return the name of a p4key that holds the latest tag changelist number for this Git Fusion server. """ return _calc_last_copied_tag_p4key_name(ctx.config.repo_name, p4gf_util.get_server_id())
def main(): """Parse the command-line arguments and report on locks.""" # pylint: disable=too-many-statements desc = _("Report the currently held locks in Git Fusion.") parser = p4gf_util.create_arg_parser(desc=desc) parser.add_argument('--test', action='store_true', help=_('invoke test mode, acquire locks and report')) parser.add_argument( '--test2', action='store_true', help=_( 'invoke test mode, acquire locks and report, set dead processes.')) args = parser.parse_args() p4gf_util.has_server_id_or_exit() server_id = p4gf_util.get_server_id() p4 = p4gf_create_p4.create_p4_temp_client() if not p4: sys.exit(1) print("Connecting to P4PORT={} as P4USER={}".format(p4.port, p4.user)) if args.test or args.test2: repo_name = "p4gf_test_status_repo" status_key_name = p4gf_p4key.calc_repo_status_p4key_name( repo_name, None) p4gf_p4key.set(p4, status_key_name, 'Push 1 completed successfully') pushid_key_name = p4gf_p4key.calc_repo_push_id_p4key_name(repo_name) p4gf_p4key.set(p4, pushid_key_name, '1') # create a process and kill it and set its dead pid as a RepoLock owner below. if args.test: # A test with nothing stale with ExitStack() as stack: stack.enter_context(p4gf_lock.ReviewsLock(p4)) stack.enter_context(p4gf_lock.RepoLock(p4, repo_name)) stack.enter_context(p4gf_git_repo_lock.read_lock(repo_name)) stack.enter_context( p4gf_git_repo_lock.write_lock(repo_name, upgrade=True)) print_lock_status(p4, server_id) else: # if args.test2 # Now a test with some DEAD processes and a stale view Lock dead_process = subprocess.Popen(['echo', 'x'], stdout=subprocess.DEVNULL) dead_process.kill() while dead_process.returncode is None: dead_process.communicate() lock2 = None with ExitStack() as stack: stack.enter_context(p4gf_lock.ReviewsLock(p4)) # first lock owner lock1 = p4gf_lock.RepoLock(p4, repo_name) # second lock owner with same group_id and a dead pid lock2 = p4gf_lock.RepoLock(p4, repo_name, group_id=lock1.group_id) lock2.process_id = dead_process.pid # acquire the first RepoLock stack.enter_context(lock1) # Use low level method to add this DEAD pid to the group's lock owners lock2.do_acquire() stack.enter_context(p4gf_git_repo_lock.read_lock(repo_name)) stack.enter_context( p4gf_git_repo_lock.write_lock(repo_name, upgrade=True)) print("Test 1:") print_lock_status(p4, server_id) p4gf_p4key.set(p4, pushid_key_name, '2') p4gf_p4key.set(p4, status_key_name, 'Push 2 failed: some error') # Finally lets set the P4GF_P4KEY_LOCK_VIEW - the least likley to be stale p4gf_p4key.set(p4, lock2.lock_key, '1') print("Test 2:") print_lock_status(p4, server_id) # Cant exit the ExistStack unless we clean this p4gf_p4key.delete(p4, lock2.lock_key) # Clean up this lock so the test may be run again p4gf_p4key.delete(p4, lock2.owners_key) # remove test keys p4gf_p4key.delete(p4, status_key_name) p4gf_p4key.delete(p4, pushid_key_name) else: print_lock_status(p4, server_id)
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 _get_server_repo_config_rev(self): """Get the config file rev for the repo from the p4key.""" key = p4gf_const.P4GF_P4KEY_REPO_SERVER_CONFIG_REV.format( repo_name=self.repo_name, server_id=p4gf_util.get_server_id()) return p4gf_util.get_p4key(self.p4, key)
def exclusive_host_view_lock(p4, view_name): '''Return an exclusive lock for the desired view, specific to the current host. ''' host_name = p4gf_util.get_server_id() return ExclusiveViewLock(p4, host_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()