def main(): """Do the thing.""" p4gf_proc.init() args = _parse_argv() sha1_last_linearized_before = _gref(GF_LTP_LAST_LINEARIZED_BEFORE) sha1_last_linearized_after = _gref(GF_LTP_LAST_LINEARIZED_AFTER) _report_begin() _require_preconditions(sha1_last_linearized_before, sha1_last_linearized_after) # Move our filter-branch ref to the end of # history that we want to rewrite. _git_tag(GF_WORKING, MASTER) # Linearize history. # This can take a while. _linearize(orig_begin_ref=GF_LTP_LAST_LINEARIZED_BEFORE, orig_end_ref=GF_WORKING, orig_parent_sha1=sha1_last_linearized_before, linearized_parent_sha1=sha1_last_linearized_after) # Advance our "last linearized" marker to # the new location. _git_tag(GF_LTP_LAST_LINEARIZED_AFTER, GF_WORKING) _git_tag(GF_LTP_LAST_LINEARIZED_BEFORE, MASTER) if args.tag_num: tag_update_before = GF_LTP_UPDATE_N_BEFORE.format(str(args.tag_num)) tag_update_after = GF_LTP_UPDATE_N_AFTER.format(str(args.tag_num)) _git_tag(tag_update_before, MASTER) _git_tag(tag_update_after, GF_WORKING) _git_tag(GF_WORKING, None) _report_end()
def main(): """create Perforce user and client for Git Fusion""" p4gf_version.log_version() try: log_l10n() p4gf_version.version_check() # pylint: disable=W0703 # Catching too general exception except Exception as e: sys.stderr.write(e.args[0] + '\n') sys.exit(1) with p4gf_create_p4.Closer(): p4 = p4gf_create_p4.create_p4() if not p4: return 2 Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port)) Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user)) p4gf_util.reset_git_enviro() p4gf_proc.init() init(p4) return 0
def main(): """Create Perforce user and client for Git Fusion.""" p4gf_version_3.log_version_extended(include_checksum=True) try: log_l10n() p4gf_version_3.version_check() except Exception as e: # pylint: disable=broad-except sys.stderr.write(e.args[0] + '\n') sys.exit(1) # To fetch the object client below we need to ensure there is a server # ID available on this system, and since we require that anyway, may as # well check it now, when we need it. p4gf_util.has_server_id_or_exit() with p4gf_create_p4.Closer(): p4 = p4gf_create_p4.create_p4_temp_client() if not p4: return 2 Verbosity.report(Verbosity.INFO, "P4PORT : {}".format(p4.port)) Verbosity.report(Verbosity.INFO, "P4USER : {}".format(p4.user)) p4gf_util.reset_git_enviro() p4gf_proc.init() try: init(p4) remove_old_temp_and_repo_clients(p4) except PermissionError: LOG.exception("unable to initialize Git Fusion") sys.stderr.write(_("File permissions error, please check ownership" " and mode of ~/.git-fusion directory.\n")) sys.exit(os.EX_NOPERM) return 0
def main(): """Do the thing.""" args = parse_argv() p4gf_proc.init() # Use current or supplied p4user, NOT git-fusion-user, for our work. # Use p4 not os.environ(), so that we can honor .p4config. p4_query_enviro = p4gf_create_p4.create_p4(port = args.p4port, user=args.p4user, warn_no_client = False) LOG.debug("P4PORT : {}".format(p4_query_enviro.port)) LOG.debug("P4USER : {}".format(p4_query_enviro.user)) p4gf_const.P4GF_USER = p4_query_enviro.user gc = GC(p4_query_enviro.port, p4_query_enviro.user, cont=args.cont, keep=args.keep, force=args.force, stdout=args.stdout, doreport=args.doreport, quiet=args.quiet) gc.gc() LOG.info("done")
def _find_true_parent(repo, head, branch_dict, work_tree): """Find the closest parent commit for the given branch reference.""" if not os.path.exists('.git'): # repository not yet initialized return head branch_names = set() # Find all non-deleted branches that Git already knows about... for branch in branch_dict.values(): if branch.git_branch_name and not branch.deleted: if repo.lookup_branch(branch.git_branch_name): branch_names.add(branch.git_branch_name) # ...excluding the branch that is being introduced branch_names.discard(head.git_branch_name()) # Turn all of those into exclusions for git-rev-list not_branches = ['^{}'.format(br) for br in branch_names] cmd = ['git', 'rev-list', '--date-order', '--parents'] + not_branches # Start git-rev-list from the new SHA1 that is being introduced. cmd.append(head.new_sha1) cwd = os.getcwd() os.chdir(work_tree) # Initialize p4gf_proc now that we've changed the cwd to the git repo # (we lack the functionality to change the cwd after the fact). p4gf_proc.init() result = p4gf_proc.popen(cmd) os.chdir(cwd) output = result['out'].strip() LOG.debug("_find_true_parent() output: %s", output) if len(output) == 0: return head # Extract the last SHA1 from the git-rev-list output, that is the true # parent of this new branch. sha1s = output[output.rfind('\n') + 1:].split() LOG.debug("_find_true_parent() first parents: %s", sha1s) parent_sha1 = sha1s[1] if len(sha1s) > 1 else sha1s[0] return PreReceiveTuple(parent_sha1, head.new_sha1, head.ref)
def create_context(args): """Create a p4gf_context for accessing Git Fusion data.""" ctx = p4gf_context.create_context(args.repo) ctx.connect_cli(LOG) p4gf_proc.init() p4gf_branch.init_case_handling(ctx.p4gf) if DEBUG: print(_("create_context: ctx.p4.port='{}' ctx.p4.user='******' .").format( ctx.p4.port, ctx.p4.user)) return (ctx.p4gf, ctx)
def main(): """Set up repo for a view.""" p4gf_util.has_server_id_or_exit() args = _parse_argv() p4gf_version_3.log_version_extended(include_checksum=True) log_l10n() if args.enablemismatchedrhs: # Git Fusion should never modify the customer's config file, and # use of this option resulted in the config file losing all of the # comments and formatting the customer had put in place. sys.stderr.write( _('The --enablemismatchedrhs option is deprecated,' ' please use enable-mismatched-rhs config file' ' option instead.\n')) sys.exit(1) repo_name_p4client = None if args.p4client: repo_name_p4client = p4gf_util.argv_to_repo_name(args.p4client) repo_name = _argv_to_repo_name(args.repo_name) p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4_temp_client() if not p4: raise RuntimeError(_('error connecting to Perforce')) LOG.debug("connected to P4 at %s", p4.port) p4gf_proc.init() try: with ExitStack() as stack: stack.enter_context(p4gf_create_p4.Closer()) p4gf_version_3.version_check() p4gf_branch.init_case_handling(p4) repo_lock = p4gf_lock.RepoLock(p4, repo_name) stack.enter_context(repo_lock) ctx = p4gf_context.create_context(repo_name) ctx.p4gf = p4 ctx.repo_lock = repo_lock initer = InitRepo(p4, repo_lock).set_repo_name(repo_name) initer.context = ctx initer.set_config_file_path(args.config) initer.set_charset(args.charset) initer.set_noclone(args.noclone) initer.set_start(args.start) stack.enter_context(ctx) initer.full_init(repo_name_p4client) except P4.P4Exception as e: _print_stderr(_('Error occurred: {exception}').format(exception=e)) sys.exit(1)
def main(): """Do the thing.""" args = parse_argv() ctx = p4gf_context.create_context(args.repo) ctx.create_config_if_missing(False) ctx.config.p4user = args.p4user ctx.config.p4port = args.p4port ctx.connect_cli(LOG) p4gf_proc.init() p4gf_branch.init_case_handling(ctx.p4gf) rollback = Rollback( ctx = ctx , change_num = args.change_num , is_preview = not args.execute , is_obliterate = args.obliterate ) rollback.rollback()
def main(): ''' Parse command line arguments and do the work of mirroring Git objects. ''' LOG.debug("main: {}, pid={}".format(p4gf_log.memory_usage(), os.getpid())) log_l10n() if 3 != len(sys.argv): sys.stderr.write(_('usage: p4gf_gitmirror_worker.py <repo> <work-queue-file>')) return 1 view_name = sys.argv[1] path = sys.argv[2] LOG.debug("reading commits from {}".format(path)) p4gf_proc.init() __do_trees(view_name, path) p4gf_proc.stop() LOG.debug("worker done for {}".format(view_name)) return 0
def main(): ''' Parse command line arguments and do the work of mirroring Git objects. ''' LOG.debug("main: {}, pid={}".format(p4gf_log.memory_usage(), os.getpid())) log_l10n() if 3 != len(sys.argv): sys.stderr.write( _('usage: p4gf_gitmirror_worker.py <repo> <work-queue-file>')) return 1 view_name = sys.argv[1] path = sys.argv[2] LOG.debug("reading commits from {}".format(path)) p4gf_proc.init() __do_trees(view_name, path) p4gf_proc.stop() LOG.debug("worker done for {}".format(view_name)) return 0
def main(): """Do the post-receive work.""" for h in ['-?', '-h', '--help']: if h in sys.argv: print(_('Git Fusion post-receive hook.')) return 2 p4gf_version_3.print_and_exit_if_argv() # If P4GF_FORK_PUSH is not set, then this is not the genuine push # payload and simply a premlinary request made by the HTTP client. # In the case of SSH, it will always be set. if p4gf_const.P4GF_FORK_PUSH not in os.environ: return 0 # Run this now to avoid the warning of p4gf_proc.init() when ps is # invoked in the lock acquisition code (and just because). p4gf_proc.init() # Indicate that the lock is about to be acquired by the upcoming # background process; the main server process will wait until the lock # acquisition is completed by the background process. LOG.debug('main() setting up forked process') with p4gf_create_p4.Closer(): p4 = p4gf_create_p4.create_p4_temp_client() repo_name = p4gf_path.cwd_to_repo_name() p4gf_log.configure_for_repo(repo_name) group_id = os.environ[p4gf_const.P4GF_FORK_PUSH] with p4gf_lock.RepoLock(p4, repo_name, group_id=group_id) as lock: lock.set_acquire_pending() # Spawn a process to do the work that pre-receive hook could not do # before git updated the references. This is an attempt to prevent # any timing issues with respect to git. LOG.debug('main() starting processing in forked process') func = functools.partial(forked_main) p4gf_proc.double_fork(func) LOG.debug('main() forked process initiated') return 0
def main(): """Copy incoming Git commits to Perforce changelists.""" _log_environ(os.environ) log_l10n() LOG.debug("main() running, pid={}".format(os.getpid())) p4gf_proc.install_stack_dumper() for h in ['-?', '-h', '--help']: if h in sys.argv: print(_('Git Fusion pre-receive hook.')) return 2 with p4gf_create_p4.Closer(): p4gf_version.print_and_exit_if_argv() p4 = p4gf_create_p4.create_p4() if not p4: return 2 p4gf_util.reset_git_enviro(p4) view_name = p4gf_util.cwd_to_view_name() view_lock = p4gf_lock.view_lock_heartbeat_only(p4, view_name) with p4gf_context.create_context(view_name, view_lock) as ctx: # this script is called by git while a context and temp clients # are already in use. Don't sabotage that context by deleting # the temp clients from here. ctx.cleanup_client_pool = False # Read each input line (usually only one unless pushing multiple branches) # and convert to a list of "tuples" from which we can assign branches. prl = [] delete_prl = [] while True: line = sys.stdin.readline() if not line: break LOG.debug('main() raw pre-receive-tuple: {}'.format(line)) prt = PreReceiveTuple.from_line(line) if int(prt.new_sha1, 16) == 0: delete_prl.append(prt) else: prl.append(prt) # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() # Reject attempt to delete any fully populated branch defined in # p4gf_config. Git Fusion never edits p4gf_config, so Git Fusion never # deletes fully populated branches. Edit p4gf_config yourself if you # want to remove a branch from history. for prt in delete_prl: git_branch_name = prt.git_branch_name() if not git_branch_name: continue branch = ctx.git_branch_name_to_branch(git_branch_name) if not branch: LOG.debug( 'attempt to delete branch {} which does not exist'. format(git_branch_name)) break if not branch.is_lightweight: raise RuntimeError( _('Cannot delete branches defined in' ' Git Fusion repo config file: {}').format( git_branch_name)) # Swarm review creates new Git merge commits. Must occur before branch # assignment so that the review reference can be moved to the new merge # commit. gsreview_coll = GSReviewCollection.from_prl(ctx, prl) if gsreview_coll: gsreview_coll.pre_copy_to_p4(prl) # Assign branches to each of the received commits for pushed branches - skip deletes. if prl: assigner = Assigner(ctx.branch_dict(), prl, ctx) assigner.assign() # For each of the heads being pushed, copy their commits to Perforce. if prl: try: err = _copy(ctx, prl=prl, assigner=assigner, gsreview_coll=gsreview_coll) # branch push if err: return _clean_exit(err) except RuntimeError as err: # Log the error. The return call below eats the error and stack trace. LOG.exception(NTR("_copy() raised exception.")) return _clean_exit(err) # For each of the heads being deleted, remove the branch definition from p4gf_config2 if delete_prl: p4gf_call_git.prohibit_interrupt(view_name, os.getpid()) try: err = _delete(ctx, delete_prl) # branch delete if err: return _clean_exit(err) except RuntimeError as err: # Log the error. The return call below eats the error and stack trace. LOG.exception(NTR("_delete() raised exception.")) return _clean_exit(err) # Process all of the tags at once. err = p4gf_tag.process_tags(ctx, prl + delete_prl) if err: return _clean_exit(err) # If we have any new Git Swarm review references that # auth/http_server must rename, send a list of such # references across process boundary, via a file. if gsreview_coll: gsreview_coll.to_file() p4gf_gc.process_garbage("at end of pre_receive_hook") p4gf_gc.report_objects(NTR("at end of pre_receive_hook")) return 0
def main(poll_only=False): """set up repo for a view view_name_git is the untranslated repo name view_name is the translated repo name """ p4gf_proc.install_stack_dumper() _log_environ(os.environ) with p4gf_server_common.ExceptionAuditLogger()\ , p4gf_create_p4.Closer(): LOG.debug(p4gf_log.memory_usage()) start_time = time.time() args = parse_args(sys.argv[1:]) if not args: return 1 is_push = 'upload' not in args.command[0] # Record the p4 user in environment. We use environment to pass to # git-invoked hook. We don't have to set ctx.authenticated_p4user because # Context.__init__() reads it from environment, which we set here. os.environ[p4gf_const.P4GF_AUTH_P4USER] = args.user # view_name_git is the untranslated repo name # view_name is the translated repo name # print "args={}".format(args) view_name_git = args.options[-1] # translate '/' ':' ' ' .. etc .. for internal view_name view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) LOG.debug("public view_name: {0} internal view_name: {1}". format(view_name_git, view_name)) p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: return 2 LOG.debug("connected to P4: %s", p4) p4gf_server_common.check_readiness(p4) p4gf_server_common.check_lock_perm(p4) if not p4gf_server_common.check_protects(p4): p4gf_server_common.raise_p4gf_perm() if p4gf_server_common.run_special_command(view_name, p4, args.user): return 0 # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() if poll_only: view_perm = None else: # Go no further, create NOTHING, if user not authorized. # We use the translated internal view name here for perm authorization required_perm = p4gf_server_common.COMMAND_TO_PERM[args.command[0]] view_perm = p4gf_group.ViewPerm.for_user_and_view(p4, args.user, view_name, required_perm) p4gf_server_common.check_authorization(p4, view_perm, args.user, args.command[0], view_name) # Create Git Fusion server depot, user, config. NOPs if already created. p4gf_init.init(p4) write_motd() # view_name is the internal view_name (identical when notExist special chars) before_lock_time = time.time() with p4gf_lock.view_lock(p4, view_name) as view_lock: after_lock_time = time.time() # Create Git Fusion per-repo client view mapping and config. # # NOPs if already created. # Create the empty directory that will hold the git repo. init_repo_status = p4gf_init_repo.init_repo(p4, view_name, view_lock) if init_repo_status == p4gf_init_repo.INIT_REPO_OK: repo_created = True elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS: repo_created = False else: return 1 # If authorization came from default, not explicit group # membership, copy that authorization to a group now. Could # not do this until after p4gf_init_repo() has a chance to # create not-yet-existing groups. if view_perm: view_perm.write_if(p4) # Now that we have valid git-fusion-user and # git-fusion-<view> client, replace our temporary P4 # connection with a more permanent Context, shared for the # remainder of this process. with p4gf_context.create_context(view_name, view_lock) as ctx: LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf) # Find directory paths to feed to git. ctx.log_context() # cd into the work directory. Not all git functions react well # to --work-tree=xxxx. cwd = os.getcwd() os.chdir(ctx.view_dirs.GIT_WORK_TREE) # Only copy from Perforce to Git if no other process is cloning # from this Git repo right now. shared_in_progress = p4gf_lock.shared_host_view_lock_exists(ctx.p4, view_name) if not shared_in_progress: # Copy any recent changes from Perforce to Git. try: LOG.debug("bare: No git-upload-pack in progress, force non-bare" " before update Git from Perforce.") p4gf_git.set_bare(False) p4gf_copy_p2g.copy_p2g_ctx(ctx) p4gf_init_repo.process_imports(ctx) # Now is also an appropriate time to clear out any stale Git # Swarm reviews. We're pre-pull, pre-push, time when we've # got exclusive write access to the Git repo, GSReviewCollection.delete_refs_for_closed_reviews(ctx) except p4gf_lock.LockCanceled as lc: LOG.warning(str(lc)) except: # Dump failure to log, BEFORE cleanup, just in case # cleanup ALSO fails and throws its own error (which # happens if we're out of memory). LOG.error(traceback.format_exc()) if repo_created: # Return to the original working directory to allow the # config code to call os.getcwd() without dying, since # we are about to delete the current working directory. os.chdir(cwd) p4gf_server_common.cleanup_client(ctx, view_name) raise if poll_only: code = os.EX_OK else: git_caller = functools.partial(_call_git, args, ctx) try: # Deep in call_git(), we grab an 'p4 reviews' lock on # ctx.clientmap's LHS. Switch that clientmap to our # full union view to prevent simultaneous 'git push'es # from clobbering each other in some shared depot # branch. Must include all lightweight branches, too. ctx.switch_client_view_to_union() exclusive = 'upload' not in args.command[0] code = p4gf_call_git.call_git( git_caller, ctx, view_name, view_lock, exclusive) if is_push: GSReviewCollection.post_push(ctx) except p4gf_atomic_lock.LockConflict as lc: sys.stderr.write("{}\n".format(lc)) code = os.EX_SOFTWARE p4gf_gc.process_garbage(NTR('at end of auth_server')) if LOG.isEnabledFor(logging.DEBUG): end_time = time.time() frm = NTR("Runtime: preparation {} ms, lock acquisition {} ms," " processing {} ms") LOG.debug(frm.format(before_lock_time - start_time, after_lock_time - before_lock_time, end_time - after_lock_time)) return code
Dump test exec args. ''' usage = _( 'Usage: p4gf_branch_id.py <repo-config-file> <git-dir> [ref ...]' '\n' '\nRuns branch-id calculation on the branches defined in' '\nrepo-config-file within the given git directory.' '\nSee debug log for results.') print(usage) exit(1) if __name__ == '__main__': if len(sys.argv) < 3: _test_usage() with p4gf_log.ExceptionLogger(): p4gf_proc.init() _refs = sys.argv[3:] if not _refs: _refs = ['master'] LOG.debug('config={} dir={}\nrefs={}' .format(sys.argv[1], sys.argv[2], _refs)) _anon_branch_func = _counter _config = configparser.ConfigParser() _config.read(sys.argv[1]) _branch_dict = p4gf_branch.dict_from_config(_config) _branch_to_old_head_sha1 = _test_return_none _git_dir = sys.argv[2] _remote_refs = ['refs/heads/' + ref for ref in _refs] _test_dump_all_commits(_branch_dict, _git_dir, _remote_refs)
def main(): """Copy incoming Git commits to Perforce changelists.""" _log_environ(os.environ) log_l10n() LOG.debug("main() running, pid={}".format(os.getpid())) p4gf_proc.install_stack_dumper() for h in ['-?', '-h', '--help']: if h in sys.argv: print(_('Git Fusion pre-receive hook.')) return 2 with p4gf_create_p4.Closer(): p4gf_version.print_and_exit_if_argv() p4 = p4gf_create_p4.create_p4() if not p4: return 2 p4gf_util.reset_git_enviro(p4) view_name = p4gf_util.cwd_to_view_name() view_lock = p4gf_lock.view_lock_heartbeat_only(p4, view_name) with p4gf_context.create_context(view_name, view_lock) as ctx: # this script is called by git while a context and temp clients # are already in use. Don't sabotage that context by deleting # the temp clients from here. ctx.cleanup_client_pool = False # Read each input line (usually only one unless pushing multiple branches) # and convert to a list of "tuples" from which we can assign branches. prl = [] delete_prl = [] while True: line = sys.stdin.readline() if not line: break LOG.debug('main() raw pre-receive-tuple: {}'.format(line)) prt = PreReceiveTuple.from_line(line) if int(prt.new_sha1, 16) == 0: delete_prl.append(prt) else: prl.append(prt) # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() # Reject attempt to delete any fully populated branch defined in # p4gf_config. Git Fusion never edits p4gf_config, so Git Fusion never # deletes fully populated branches. Edit p4gf_config yourself if you # want to remove a branch from history. for prt in delete_prl: git_branch_name = prt.git_branch_name() if not git_branch_name: continue branch = ctx.git_branch_name_to_branch(git_branch_name) if not branch: LOG.debug('attempt to delete branch {} which does not exist' .format(git_branch_name)) break if not branch.is_lightweight: raise RuntimeError(_('Cannot delete branches defined in' ' Git Fusion repo config file: {}') .format(git_branch_name)) # Swarm review creates new Git merge commits. Must occur before branch # assignment so that the review reference can be moved to the new merge # commit. gsreview_coll = GSReviewCollection.from_prl(ctx, prl) if gsreview_coll: gsreview_coll.pre_copy_to_p4(prl) # Assign branches to each of the received commits for pushed branches - skip deletes. if prl: assigner = Assigner(ctx.branch_dict(), prl, ctx) assigner.assign() # For each of the heads being pushed, copy their commits to Perforce. if prl: try: err = _copy( ctx , prl = prl , assigner = assigner , gsreview_coll = gsreview_coll) # branch push if err: return _clean_exit(err) except RuntimeError as err: # Log the error. The return call below eats the error and stack trace. LOG.exception(NTR("_copy() raised exception.")) return _clean_exit(err) # For each of the heads being deleted, remove the branch definition from p4gf_config2 if delete_prl: p4gf_call_git.prohibit_interrupt(view_name, os.getpid()) try: err = _delete(ctx, delete_prl) # branch delete if err: return _clean_exit(err) except RuntimeError as err: # Log the error. The return call below eats the error and stack trace. LOG.exception(NTR("_delete() raised exception.")) return _clean_exit(err) # Process all of the tags at once. err = p4gf_tag.process_tags(ctx, prl + delete_prl) if err: return _clean_exit(err) # If we have any new Git Swarm review references that # auth/http_server must rename, send a list of such # references across process boundary, via a file. if gsreview_coll: gsreview_coll.to_file() p4gf_gc.process_garbage("at end of pre_receive_hook") p4gf_gc.report_objects(NTR("at end of pre_receive_hook")) return 0
def _wsgi_app(environ, start_response): """ WSGI application to process the incoming Git client request. This is nearly equivalent to p4gf_auth_server.main() with the exception of input validation and error handling. """ p4gf_log.record_http(environ) p4gf_version.log_version() _log_environ(environ) p4gf_version.version_check() LOG.debug("processing HTTP request, pid={}".format(os.getpid())) # Keep the content type to exactly 'text/plain' so there is at least # the remote chance that Git might show our error messages (does not # appear to work in practice, however). headers = [('Content-Type', 'text/plain')] encoding = sys.getfilesystemencoding() if encoding == 'ascii': # This encoding is wrong and will eventually lead to problems. LOG.error("Using 'ascii' file encoding will ultimately result in errors, " "please set LANG/LC_ALL to 'utf-8' in web server configuration.") start_response(_('500 Internal Server Error'), headers) return [b"Filesystem encoding not set to acceptable value.\n"] # Sanity check the request. for (name, status, msg) in _REQUIRED_HTTP_PARAMS: if name not in environ: start_response(status, headers) return [msg.encode('UTF-8')] input_name = environ['wsgi.input'] # Extract the view_name_git by removing the expected git request suffixes path_info = environ['PATH_INFO'] git_suffixes = ['/info/refs', '/HEAD', '/git-upload-pack', '/git-receive-pack'] path_end = len(path_info) for suffix in git_suffixes: try: path_end = path_info.index(suffix) break except ValueError: pass # slice away the leading slash and the trailing git request suffixes view_name_git = path_info[1:path_end] # and remove the view_name_git from the front of PATH_INFO environ['PATH_INFO'] = path_info[path_end:] LOG.debug("new PATH_INFO {0} view_name_git {1}".format(environ['PATH_INFO'], view_name_git)) if not view_name_git: start_response(_('400 Bad Request'), headers) msg = _('Missing required repository name in URL\n') return [msg.encode('UTF-8')] # translate '/' ':' ' ' .. etc .. for internal view_name view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) LOG.debug("public view_name: {0} internal view_name: {1}".format(view_name_git, view_name)) audit_logger = p4gf_server_common.ExceptionAuditLogger() p4_closer = p4gf_create_p4.Closer() sink = OutputSink() temp_deleter = deleting(input_name) mirror_closer = unmirror(view_name) with audit_logger \ , p4_closer \ , sink \ , temp_deleter \ , mirror_closer: LOG.debug(p4gf_log.memory_usage()) start_time = time.time() p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: start_response(_('500 Internal Server Error'), headers) return [b"Perforce connection failed\n"] LOG.debug("connected to P4: %s", p4) p4gf_server_common.check_readiness(p4) p4gf_server_common.check_lock_perm(p4) if not p4gf_server_common.check_protects(p4): p4gf_server_common.raise_p4gf_perm() user = environ['REMOTE_USER'] if p4gf_server_common.run_special_command(view_name, p4, user): start_response(_('200 OK'), headers) return [sink.readall()] command = _get_command(environ) if not command: start_response(_('400 Bad Request'), headers) return [b"Unrecognized service\n"] # Other places in the Perforce-to-Git phase will need to know the # name of client user, so set that here. As for Git-to-Perforce, # that is handled later by setting the REMOTE_USER envar. Notice # also that we're setting os.environ and not 'environ'. os.environ[p4gf_const.P4GF_AUTH_P4USER] = user # Likewise, some code needs a hint that the request is coming over # one protocol (HTTP) or the other (SSH). os.environ['REMOTE_ADDR'] = environ['REMOTE_ADDR'] # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() # Go no further, create NOTHING, if user not authorized. # We use the translated internal view name here for perm authorization required_perm = p4gf_server_common.COMMAND_TO_PERM[command] view_perm = p4gf_group.ViewPerm.for_user_and_view(p4, user, view_name, required_perm) try: p4gf_server_common.check_authorization(p4, view_perm, user, command, view_name) except p4gf_server_common.CommandError as ce: start_response(_('403 Forbidden'), headers) return [str(ce).encode('UTF-8')] # Create Git Fusion server depot, user, config. NOPs if already created. p4gf_init.init(p4) before_lock_time = time.time() with p4gf_lock.view_lock(p4, view_name) as view_lock: after_lock_time = time.time() # Create Git Fusion per-repo client view mapping and config. init_repo_status = p4gf_init_repo.init_repo(p4, view_name, view_lock) if init_repo_status == p4gf_init_repo.INIT_REPO_OK: repo_created = True elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS: repo_created = False elif init_repo_status == p4gf_init_repo.INIT_REPO_NOVIEW: start_response(_('404 Not Found'), headers) return [sink.readall()] else: start_response(_('500 Internal Server Error'), headers) return [b"Repository initialization failed\n"] # If authorization came from default, not explicit group # membership, copy that authorization to a group now. Could # not do this until after p4gf_init_repo() has a chance to # create not-yet-existing groups. if view_perm: view_perm.write_if(p4) # Now that we have valid git-fusion-user and # git-fusion-<view> client, replace our temporary P4 # connection with a more permanent Context, shared for the # remainder of this process. with p4gf_context.create_context(view_name, view_lock) as ctx: LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf) ctx.log_context() # cd into the work directory. Not all git functions react well # to --work-tree=xxxx. cwd = os.getcwd() os.chdir(ctx.view_dirs.GIT_WORK_TREE) # Only copy from Perforce to Git if no other process is cloning # from this Git repo right now. shared_in_progress = p4gf_lock.shared_host_view_lock_exists(ctx.p4, view_name) if not shared_in_progress: # Copy any recent changes from Perforce to Git. try: LOG.debug("bare: No git-upload-pack in progress, force non-bare" " before update Git from Perforce.") p4gf_git.set_bare(False) p4gf_copy_p2g.copy_p2g_ctx(ctx) p4gf_init_repo.process_imports(ctx) # Now is also an appropriate time to clear out any stale Git # Swarm reviews. We're pre-pull, pre-push, time when we've # got exclusive write access to the Git repo, GSReviewCollection.delete_refs_for_closed_reviews(ctx) except p4gf_lock.LockCanceled as lc: LOG.warning(str(lc)) except: # Dump failure to log, BEFORE cleanup, just in case # cleanup ALSO fails and throws its own error (which # happens if we're out of memory). LOG.error(traceback.format_exc()) if repo_created: # Return to the original working directory to allow the # config code to call os.getcwd() without dying, since # we are about to delete the current working directory. os.chdir(cwd) p4gf_server_common.cleanup_client(ctx, view_name) raise try: exclusive = 'upload' not in command is_push = 'upload' not in command git_caller = functools.partial(_call_git, input_name, environ, ctx) p4gf_call_git.call_git(git_caller, ctx, view_name, view_lock, exclusive) if is_push: GSReviewCollection.post_push(ctx) except p4gf_atomic_lock.LockConflict as lc: start_response(_('500 Internal Server Error'), headers) return ["{}".format(lc).encode('UTF-8')] p4gf_gc.process_garbage('at end of auth_server') if LOG.isEnabledFor(logging.DEBUG): end_time = time.time() frm = NTR('Runtime: preparation {} ms, lock acquisition {} ms, processing {} ms') LOG.debug(frm.format(before_lock_time - start_time, after_lock_time - before_lock_time, end_time - after_lock_time)) return []
def main(): """set up repo for a view""" p4gf_util.has_server_id_or_exit() args = _parse_argv() p4gf_version.log_version() log_l10n() # !!! view_name_git the untranslated repo name # !!! view_name the translated repo name view_name_p4client = None if args.p4client: view_name_p4client = p4gf_util.argv_to_view_name(args.p4client) view_name_git = p4gf_util.argv_to_view_name(args.view) #strip leading '/' to conform with p4gf_auth_server behavior if view_name_git[0] == '/': view_name_git = view_name_git[1:] view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) p4gf_gitmirror.setup_spawn(view_name) p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: return INIT_REPO_NOVIEW LOG.debug("connected to P4 at %s", p4.port) p4gf_proc.init() try: with p4gf_create_p4.Closer(): p4gf_version.version_check() with p4gf_lock.view_lock(p4, view_name) as view_lock: # Ensure we have a sane environment. p4gf_init.init(p4) # Now that we can trust that the git-fusion--p4 client exists, # switch to that. Change takes effect immediately, don't need to # re-run p4.connect(). p4.client = p4gf_util.get_object_client_name() # If local config file specified, validate it and store in # Perforce now. Even if client exists (aka repo was already # inited), this is one way for an admin to modify an existing # repo's config. if args.config: if not os.path.exists(args.config): _print_stderr(_("error: missing config file '{}'").format(args.config)) return INIT_REPO_CONFIG_FILE_MISSING with Validator.from_local_file(view_name, p4, args.config) as validator: if not validator.is_valid(args.enablemismatchedrhs): return INIT_REPO_CONFIG_FILE_BAD p4gf_config.create_file_repo_with_contents(p4, view_name, args.config) elif args.charset and not Validator.valid_charset(args.charset): _print_stderr(_("error: invalid charset: {}").format(args.charset)) return INIT_REPO_BAD_CHARSET # Initialize the repository if necessary. print(_("Initializing '{}'...").format(view_name)) r = init_repo(p4, view_name, view_lock, args.charset, args.enablemismatchedrhs, view_name_p4client) if r > INIT_REPO_OK: return r print(_("Initialization complete.")) # Write --enablemismatchedrhs to config file if args.enablemismatchedrhs: config = p4gf_config.read_repo(p4, view_name) config[p4gf_config.SECTION_REPO]\ [p4gf_config.KEY_ENABLE_MISMATCHED_RHS] = str(True) p4gf_config.write_repo_if(p4, p4.fetch_client(), view_name, config) # Populate the repo from Perforce unless --noclone. if not args.noclone: return populate_repo(view_name, view_lock, args.start) except P4.P4Exception as e: _print_stderr(_('Error occurred: {}').format(e)) return INIT_REPO_EXISTS
def do_it(self): """Perform all of the setup, processing, and clean up. :rtype: int :return: status code for the process upon exit. """ p4gf_util.log_environ(LOG, os.environ, self.label) log_l10n() p4gf_proc.install_stack_dumper() # Kick off garbage collection debugging, if enabled. p4gf_mem_gc.init_gc() # Use ExitStack to avoid deeply nested code. with ExitStack() as stack: stack.enter_context(p4gf_create_p4.Closer()) p4 = p4gf_create_p4.create_p4_temp_client() if not p4: return 2 repo_name = p4gf_path.cwd_to_repo_name() p4gf_util.reset_git_enviro() # Initialize the external process launcher early, before # allocating lots of memory, and just after all other # conditions have been checked. p4gf_proc.init() # Assume that something bad will happen (especially with preflight). exit_code = os.EX_SOFTWARE try: p4gf_log.configure_for_repo(repo_name) gid = os.environ[p4gf_const.P4GF_FORK_PUSH] self.before_p4key_lock(repo_name) with p4gf_lock.RepoLock(p4, repo_name, group_id=gid) as repo_lock: # Work to be done with the p4key lock... self.context = p4gf_context.create_context(repo_name) self.context.p4gf = p4 self.context.repo_lock = repo_lock self.context.foruser = os.getenv(p4gf_const.P4GF_FORUSER) stack.enter_context(self.context) self.before() exit_code = self.process() if self.after_requires_write_lock(): # Work to be done without the p4key lock, but with the # write lock. Note that we release the p4key lock # before acquiring the write lock to avoid deadlock # with the foreground process, which always gets the # repo read/write lock _before_ acquiring the p4key # lock. Hence all this complication with the locks. with p4gf_git_repo_lock.write_lock(repo_name): self.after(exit_code) else: # The after() method does not need a write lock... self.after(exit_code) finally: self.cleanup() p4gf_proc.stop() # Random tasks after all of the locks have been released. msg = NTR("at end of {hook}").format(hook=self.label) p4gf_mem_gc.process_garbage(msg) p4gf_mem_gc.report_objects(msg) return exit_code
def _wsgi_app(environ, start_response): """ WSGI application to process the incoming Git client request. This is nearly equivalent to p4gf_auth_server.main() with the exception of input validation and error handling. """ p4gf_log.record_http(environ) p4gf_version.log_version() _log_environ(environ) p4gf_version.version_check() LOG.debug("processing HTTP request, pid={}".format(os.getpid())) # Keep the content type to exactly 'text/plain' so there is at least # the remote chance that Git might show our error messages (does not # appear to work in practice, however). headers = [('Content-Type', 'text/plain')] encoding = sys.getfilesystemencoding() if encoding == 'ascii': # This encoding is wrong and will eventually lead to problems. LOG.error( "Using 'ascii' file encoding will ultimately result in errors, " "please set LANG/LC_ALL to 'utf-8' in web server configuration.") start_response(_('500 Internal Server Error'), headers) return [b"Filesystem encoding not set to acceptable value.\n"] # Sanity check the request. for (name, status, msg) in _REQUIRED_HTTP_PARAMS: if name not in environ: start_response(status, headers) return [msg.encode('UTF-8')] input_name = environ['wsgi.input'] # Extract the view_name_git by removing the expected git request suffixes path_info = environ['PATH_INFO'] git_suffixes = [ '/info/refs', '/HEAD', '/git-upload-pack', '/git-receive-pack' ] path_end = len(path_info) for suffix in git_suffixes: try: path_end = path_info.index(suffix) break except ValueError: pass # slice away the leading slash and the trailing git request suffixes view_name_git = path_info[1:path_end] # and remove the view_name_git from the front of PATH_INFO environ['PATH_INFO'] = path_info[path_end:] LOG.debug("new PATH_INFO {0} view_name_git {1}".format( environ['PATH_INFO'], view_name_git)) if not view_name_git: start_response(_('400 Bad Request'), headers) msg = _('Missing required repository name in URL\n') return [msg.encode('UTF-8')] # translate '/' ':' ' ' .. etc .. for internal view_name view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) LOG.debug("public view_name: {0} internal view_name: {1}".format( view_name_git, view_name)) audit_logger = p4gf_server_common.ExceptionAuditLogger() p4_closer = p4gf_create_p4.Closer() sink = OutputSink() temp_deleter = deleting(input_name) mirror_closer = unmirror(view_name) with audit_logger \ , p4_closer \ , sink \ , temp_deleter \ , mirror_closer: LOG.debug(p4gf_log.memory_usage()) start_time = time.time() p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: start_response(_('500 Internal Server Error'), headers) return [b"Perforce connection failed\n"] LOG.debug("connected to P4: %s", p4) p4gf_server_common.check_readiness(p4) p4gf_server_common.check_lock_perm(p4) if not p4gf_server_common.check_protects(p4): p4gf_server_common.raise_p4gf_perm() user = environ['REMOTE_USER'] if p4gf_server_common.run_special_command(view_name, p4, user): start_response(_('200 OK'), headers) return [sink.readall()] command = _get_command(environ) if not command: start_response(_('400 Bad Request'), headers) return [b"Unrecognized service\n"] # Other places in the Perforce-to-Git phase will need to know the # name of client user, so set that here. As for Git-to-Perforce, # that is handled later by setting the REMOTE_USER envar. Notice # also that we're setting os.environ and not 'environ'. os.environ[p4gf_const.P4GF_AUTH_P4USER] = user # Likewise, some code needs a hint that the request is coming over # one protocol (HTTP) or the other (SSH). os.environ['REMOTE_ADDR'] = environ['REMOTE_ADDR'] # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() # Go no further, create NOTHING, if user not authorized. # We use the translated internal view name here for perm authorization required_perm = p4gf_server_common.COMMAND_TO_PERM[command] view_perm = p4gf_group.ViewPerm.for_user_and_view( p4, user, view_name, required_perm) try: p4gf_server_common.check_authorization(p4, view_perm, user, command, view_name) except p4gf_server_common.CommandError as ce: start_response(_('403 Forbidden'), headers) return [str(ce).encode('UTF-8')] # Create Git Fusion server depot, user, config. NOPs if already created. p4gf_init.init(p4) before_lock_time = time.time() with p4gf_lock.view_lock(p4, view_name) as view_lock: after_lock_time = time.time() # Create Git Fusion per-repo client view mapping and config. init_repo_status = p4gf_init_repo.init_repo( p4, view_name, view_lock) if init_repo_status == p4gf_init_repo.INIT_REPO_OK: repo_created = True elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS: repo_created = False elif init_repo_status == p4gf_init_repo.INIT_REPO_NOVIEW: start_response(_('404 Not Found'), headers) return [sink.readall()] else: start_response(_('500 Internal Server Error'), headers) return [b"Repository initialization failed\n"] # If authorization came from default, not explicit group # membership, copy that authorization to a group now. Could # not do this until after p4gf_init_repo() has a chance to # create not-yet-existing groups. if view_perm: view_perm.write_if(p4) # Now that we have valid git-fusion-user and # git-fusion-<view> client, replace our temporary P4 # connection with a more permanent Context, shared for the # remainder of this process. with p4gf_context.create_context(view_name, view_lock) as ctx: LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf) ctx.log_context() # cd into the work directory. Not all git functions react well # to --work-tree=xxxx. cwd = os.getcwd() os.chdir(ctx.view_dirs.GIT_WORK_TREE) # Only copy from Perforce to Git if no other process is cloning # from this Git repo right now. shared_in_progress = p4gf_lock.shared_host_view_lock_exists( ctx.p4, view_name) if not shared_in_progress: # Copy any recent changes from Perforce to Git. try: LOG.debug( "bare: No git-upload-pack in progress, force non-bare" " before update Git from Perforce.") p4gf_git.set_bare(False) p4gf_copy_p2g.copy_p2g_ctx(ctx) p4gf_init_repo.process_imports(ctx) # Now is also an appropriate time to clear out any stale Git # Swarm reviews. We're pre-pull, pre-push, time when we've # got exclusive write access to the Git repo, GSReviewCollection.delete_refs_for_closed_reviews(ctx) except p4gf_lock.LockCanceled as lc: LOG.warning(str(lc)) except: # Dump failure to log, BEFORE cleanup, just in case # cleanup ALSO fails and throws its own error (which # happens if we're out of memory). LOG.error(traceback.format_exc()) if repo_created: # Return to the original working directory to allow the # config code to call os.getcwd() without dying, since # we are about to delete the current working directory. os.chdir(cwd) p4gf_server_common.cleanup_client(ctx, view_name) raise try: exclusive = 'upload' not in command is_push = 'upload' not in command git_caller = functools.partial(_call_git, input_name, environ, ctx) p4gf_call_git.call_git(git_caller, ctx, view_name, view_lock, exclusive) if is_push: GSReviewCollection.post_push(ctx) except p4gf_atomic_lock.LockConflict as lc: start_response(_('500 Internal Server Error'), headers) return ["{}".format(lc).encode('UTF-8')] p4gf_gc.process_garbage('at end of auth_server') if LOG.isEnabledFor(logging.DEBUG): end_time = time.time() frm = NTR( 'Runtime: preparation {} ms, lock acquisition {} ms, processing {} ms' ) LOG.debug( frm.format(before_lock_time - start_time, after_lock_time - before_lock_time, end_time - after_lock_time)) return []
def main(poll_only=False): """set up repo for a view view_name_git is the untranslated repo name view_name is the translated repo name """ p4gf_proc.install_stack_dumper() _log_environ(os.environ) with p4gf_server_common.ExceptionAuditLogger()\ , p4gf_create_p4.Closer(): LOG.debug(p4gf_log.memory_usage()) start_time = time.time() args = parse_args(sys.argv[1:]) if not args: return 1 is_push = 'upload' not in args.command[0] # Record the p4 user in environment. We use environment to pass to # git-invoked hook. We don't have to set ctx.authenticated_p4user because # Context.__init__() reads it from environment, which we set here. os.environ[p4gf_const.P4GF_AUTH_P4USER] = args.user # view_name_git is the untranslated repo name # view_name is the translated repo name # print "args={}".format(args) view_name_git = args.options[-1] # translate '/' ':' ' ' .. etc .. for internal view_name view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) LOG.debug("public view_name: {0} internal view_name: {1}".format( view_name_git, view_name)) p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: return 2 LOG.debug("connected to P4: %s", p4) p4gf_server_common.check_readiness(p4) p4gf_server_common.check_lock_perm(p4) if not p4gf_server_common.check_protects(p4): p4gf_server_common.raise_p4gf_perm() if p4gf_server_common.run_special_command(view_name, p4, args.user): return 0 # Initialize the external process launcher early, before allocating lots # of memory, and just after all other conditions have been checked. p4gf_proc.init() # Prepare for possible spawn of GitMirror worker process by forking # now before allocating lots of memory. p4gf_gitmirror.setup_spawn(view_name) # Kick off garbage collection debugging, if enabled. p4gf_gc.init_gc() if poll_only: view_perm = None else: # Go no further, create NOTHING, if user not authorized. # We use the translated internal view name here for perm authorization required_perm = p4gf_server_common.COMMAND_TO_PERM[args.command[0]] view_perm = p4gf_group.ViewPerm.for_user_and_view( p4, args.user, view_name, required_perm) p4gf_server_common.check_authorization(p4, view_perm, args.user, args.command[0], view_name) # Create Git Fusion server depot, user, config. NOPs if already created. p4gf_init.init(p4) write_motd() # view_name is the internal view_name (identical when notExist special chars) before_lock_time = time.time() with p4gf_lock.view_lock(p4, view_name) as view_lock: after_lock_time = time.time() # Create Git Fusion per-repo client view mapping and config. # # NOPs if already created. # Create the empty directory that will hold the git repo. init_repo_status = p4gf_init_repo.init_repo( p4, view_name, view_lock) if init_repo_status == p4gf_init_repo.INIT_REPO_OK: repo_created = True elif init_repo_status == p4gf_init_repo.INIT_REPO_EXISTS: repo_created = False else: return 1 # If authorization came from default, not explicit group # membership, copy that authorization to a group now. Could # not do this until after p4gf_init_repo() has a chance to # create not-yet-existing groups. if view_perm: view_perm.write_if(p4) # Now that we have valid git-fusion-user and # git-fusion-<view> client, replace our temporary P4 # connection with a more permanent Context, shared for the # remainder of this process. with p4gf_context.create_context(view_name, view_lock) as ctx: LOG.debug("reconnected to P4, p4gf=%s", ctx.p4gf) # Find directory paths to feed to git. ctx.log_context() # cd into the work directory. Not all git functions react well # to --work-tree=xxxx. cwd = os.getcwd() os.chdir(ctx.view_dirs.GIT_WORK_TREE) # Only copy from Perforce to Git if no other process is cloning # from this Git repo right now. shared_in_progress = p4gf_lock.shared_host_view_lock_exists( ctx.p4, view_name) if not shared_in_progress: # Copy any recent changes from Perforce to Git. try: LOG.debug( "bare: No git-upload-pack in progress, force non-bare" " before update Git from Perforce.") p4gf_git.set_bare(False) p4gf_copy_p2g.copy_p2g_ctx(ctx) p4gf_init_repo.process_imports(ctx) # Now is also an appropriate time to clear out any stale Git # Swarm reviews. We're pre-pull, pre-push, time when we've # got exclusive write access to the Git repo, GSReviewCollection.delete_refs_for_closed_reviews(ctx) except p4gf_lock.LockCanceled as lc: LOG.warning(str(lc)) except: # Dump failure to log, BEFORE cleanup, just in case # cleanup ALSO fails and throws its own error (which # happens if we're out of memory). LOG.error(traceback.format_exc()) if repo_created: # Return to the original working directory to allow the # config code to call os.getcwd() without dying, since # we are about to delete the current working directory. os.chdir(cwd) p4gf_server_common.cleanup_client(ctx, view_name) raise if poll_only: code = os.EX_OK else: git_caller = functools.partial(_call_git, args, ctx) try: # Deep in call_git(), we grab an 'p4 reviews' lock on # ctx.clientmap's LHS. Switch that clientmap to our # full union view to prevent simultaneous 'git push'es # from clobbering each other in some shared depot # branch. Must include all lightweight branches, too. ctx.switch_client_view_to_union() exclusive = 'upload' not in args.command[0] code = p4gf_call_git.call_git(git_caller, ctx, view_name, view_lock, exclusive) if is_push: GSReviewCollection.post_push(ctx) except p4gf_atomic_lock.LockConflict as lc: sys.stderr.write("{}\n".format(lc)) code = os.EX_SOFTWARE p4gf_gc.process_garbage(NTR('at end of auth_server')) if LOG.isEnabledFor(logging.DEBUG): end_time = time.time() frm = NTR("Runtime: preparation {} ms, lock acquisition {} ms," " processing {} ms") LOG.debug( frm.format(before_lock_time - start_time, after_lock_time - before_lock_time, end_time - after_lock_time)) return code
def main(): """set up repo for a view""" p4gf_util.has_server_id_or_exit() args = _parse_argv() p4gf_version.log_version() log_l10n() # !!! view_name_git the untranslated repo name # !!! view_name the translated repo name view_name_p4client = None if args.p4client: view_name_p4client = p4gf_util.argv_to_view_name(args.p4client) view_name_git = p4gf_util.argv_to_view_name(args.view) #strip leading '/' to conform with p4gf_auth_server behavior if view_name_git[0] == '/': view_name_git = view_name_git[1:] view_name = p4gf_translate.TranslateReponame.git_to_repo(view_name_git) p4gf_gitmirror.setup_spawn(view_name) p4gf_util.reset_git_enviro() p4 = p4gf_create_p4.create_p4() if not p4: return INIT_REPO_NOVIEW LOG.debug("connected to P4 at %s", p4.port) p4gf_proc.init() try: with p4gf_create_p4.Closer(): p4gf_version.version_check() with p4gf_lock.view_lock(p4, view_name) as view_lock: # Ensure we have a sane environment. p4gf_init.init(p4) # Now that we can trust that the git-fusion--p4 client exists, # switch to that. Change takes effect immediately, don't need to # re-run p4.connect(). p4.client = p4gf_util.get_object_client_name() # If local config file specified, validate it and store in # Perforce now. Even if client exists (aka repo was already # inited), this is one way for an admin to modify an existing # repo's config. if args.config: if not os.path.exists(args.config): _print_stderr( _("error: missing config file '{}'").format( args.config)) return INIT_REPO_CONFIG_FILE_MISSING with Validator.from_local_file(view_name, p4, args.config) as validator: if not validator.is_valid(args.enablemismatchedrhs): return INIT_REPO_CONFIG_FILE_BAD p4gf_config.create_file_repo_with_contents( p4, view_name, args.config) elif args.charset and not Validator.valid_charset( args.charset): _print_stderr( _("error: invalid charset: {}").format(args.charset)) return INIT_REPO_BAD_CHARSET # Initialize the repository if necessary. print(_("Initializing '{}'...").format(view_name)) r = init_repo(p4, view_name, view_lock, args.charset, args.enablemismatchedrhs, view_name_p4client) if r > INIT_REPO_OK: return r print(_("Initialization complete.")) # Write --enablemismatchedrhs to config file if args.enablemismatchedrhs: config = p4gf_config.read_repo(p4, view_name) config[p4gf_config.SECTION_REPO]\ [p4gf_config.KEY_ENABLE_MISMATCHED_RHS] = str(True) p4gf_config.write_repo_if(p4, p4.fetch_client(), view_name, config) # Populate the repo from Perforce unless --noclone. if not args.noclone: return populate_repo(view_name, view_lock, args.start) except P4.P4Exception as e: _print_stderr(_('Error occurred: {}').format(e)) return INIT_REPO_EXISTS