Exemplo n.º 1
0
void SG_getopt__print_option(SG_context* pCtx, SG_console_stream cs, SG_getopt_option* opt, const char * overrideDesc)
{
	SG_string *opts;

	if (opt == NULL)
    {
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "?")  );
		return;
    }

	SG_ERR_CHECK(  SG_string__alloc(pCtx, &opts)  );

	/* We have a valid option which may or may not have a "short
		name" (a single-character alias for the long option). */
	if (opt->optch <= 255)
		SG_ERR_CHECK(  SG_string__sprintf(pCtx, opts, "-%c [--%s]", opt->optch, opt->pStringName)  );
	else
		SG_ERR_CHECK(  SG_string__sprintf(pCtx, opts, "--%s", opt->pStringName)  );

	if (opt->has_arg)
		SG_ERR_CHECK(  SG_string__append__sz(pCtx, opts, " ARG")  );

	if (overrideDesc)
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "%-20s :  %s\n", SG_string__sz(opts), overrideDesc)  );
	else
		SG_ERR_IGNORE(  SG_console(pCtx, cs, "%-20s :  %s\n", SG_string__sz(opts), opt->pStringDescription)  );


fail:
	SG_STRING_NULLFREE(pCtx, opts);
}
Exemplo n.º 2
0
void SG_vfile__end(
	SG_context* pCtx,
	SG_vfile** ppvf,
	const SG_vhash* pvh
	)
{
	SG_string* pstr = NULL;
	SG_vfile* pvf = NULL;

	SG_NULLARGCHECK_RETURN(ppvf);

	pvf = *ppvf;

	if (pvh)
	{
		SG_ARGCHECK_RETURN( !(pvf->mode & SG_FILE_RDONLY) , pvh );

		SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr)  );

		SG_ERR_CHECK(  SG_vhash__to_json(pCtx, pvh,pstr)  );

		SG_ERR_CHECK(  SG_file__seek(pCtx, pvf->pFile, 0)  );

		SG_ERR_CHECK(  SG_file__truncate(pCtx, pvf->pFile)  );

#if TRACE_VFILE
		SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Writing %d bytes to file.\n",
								   SG_string__length_in_bytes(pstr))  );
#endif

		SG_ERR_CHECK(  SG_file__write(pCtx, pvf->pFile, SG_string__length_in_bytes(pstr), (const SG_byte *)SG_string__sz(pstr), NULL)  );
		SG_STRING_NULLFREE(pCtx, pstr);
	}
	else
	{
		if (!(pvf->mode & SG_FILE_RDONLY))
		{
			SG_ERR_CHECK(  SG_file__seek(pCtx, pvf->pFile, 0)  );

			SG_ERR_CHECK(  SG_file__truncate(pCtx, pvf->pFile)  );

#if TRACE_VFILE
			SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "VFileEnd: Truncating file.\n")  );
#endif
		}
	}

	SG_FILE_NULLCLOSE(pCtx, pvf->pFile);

	SG_NULLFREE(pCtx, pvf);
	*ppvf = NULL;

	return;
fail:
	SG_STRING_NULLFREE(pCtx, pstr);
}
void _sg_mrg__copy_wc_to_temp_file(SG_context * pCtx, SG_mrg * pMrg,
								   SG_mrg_cset_entry * pMrgCSetEntry,
								   const SG_pathname * pPathTempFile)
{
	sg_wc_liveview_item * pLVI;
	SG_string * pStringRepoPath = NULL;
	SG_pathname * pPathInWC = NULL;
	SG_bool bExists;
	SG_bool bKnown;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx,pPathTempFile,&bExists,NULL,NULL)  );
	if (bExists)
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Skipping copy of WC version to [%s]\n",
								   SG_pathname__sz(pPathTempFile))  );
#endif
		return;
	}

	// Find the absolute path of the WD version of the file.
	SG_ERR_CHECK(  sg_wc_tx__liveview__fetch_random_item(pCtx, pMrg->pWcTx,
														 pMrgCSetEntry->uiAliasGid,
														 &bKnown, &pLVI)  );
	SG_ASSERT_RELEASE_FAIL(  (bKnown)  );
	SG_ERR_CHECK(  sg_wc_tx__liveview__compute_live_repo_path(pCtx, pMrg->pWcTx, pLVI,
															  &pStringRepoPath)  );
	SG_ERR_CHECK(  sg_wc_db__path__repopath_to_absolute(pCtx, pMrg->pWcTx->pDb,
														pStringRepoPath,
														&pPathInWC)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
							   "Copying WC version [%s] to [%s]\n",
							   SG_string__sz(pStringRepoPath),
							   SG_pathname__sz(pPathTempFile))  );
#endif

	// Ideally, when we create this TEMP file it should be read-only.
	// Afterall, it does represent a historical version of the file and
	// it should only be used as INPUT to whatever merge tool the user
	// has configured.  So it should be read-only.  This might allow
	// a GUI merge tool to show locks/whatever and/or prevent accidental
	// editing of these files.
	//
	// However, this can cause an "Access is Denied" error on Windows
	// when we get ready to delete the contents of the TEMP directory.
	// We'll deal with that there rather than here.

	SG_ERR_CHECK(  SG_fsobj__copy_file(pCtx, pPathInWC, pPathTempFile, 0400)  );

fail:
	SG_STRING_NULLFREE(pCtx, pStringRepoPath);
	SG_PATHNAME_NULLFREE(pCtx, pPathInWC);
}
void SG_sync_remote__push_add(
	SG_context* pCtx,
	const char* pszPushId,
	SG_repo* pRepo,
	const char* psz_fragball_name,
	SG_vhash** ppResult
	)
{
	SG_staging* pStaging = NULL;
	SG_vhash* pvh_status = NULL;

#if TRACE_SYNC_REMOTE
	SG_int64 startTime;
	SG_int64 endTime;
	double seconds;
#endif

	SG_NULLARGCHECK_RETURN(pszPushId);
	SG_NULLARGCHECK_RETURN(ppResult);

	SG_ERR_CHECK(  SG_staging__open(pCtx, pszPushId, &pStaging)  );

#if TRACE_SYNC_REMOTE
	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx, &startTime)  );
#endif

	SG_ERR_CHECK(  SG_staging__slurp_fragball(pCtx, pStaging, psz_fragball_name)  );

#if TRACE_SYNC_REMOTE
	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx, &endTime)  );
	seconds = ((double)endTime-(double)startTime)/1000;
	SG_ERR_CHECK(  SG_console(pCtx, SG_CS_STDERR, "Fragball slurp took %1.3f seconds\n", seconds)  );
	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx, &startTime)  );
#endif

	SG_ERR_CHECK(  SG_staging__check_status(pCtx, pStaging, pRepo,
		SG_TRUE, SG_TRUE, SG_TRUE, SG_TRUE, SG_FALSE,
		&pvh_status)  );

#if TRACE_SYNC_REMOTE
	SG_ERR_CHECK(  SG_time__get_milliseconds_since_1970_utc(pCtx, &endTime)  );
	seconds = ((double)endTime-(double)startTime)/1000;
	SG_ERR_CHECK(  SG_console(pCtx, SG_CS_STDERR, "Status check after fragball slurp took %1.3f seconds\n", seconds)  );
#endif

	*ppResult = pvh_status;
	pvh_status = NULL;

	/* fallthru */

fail:
	SG_VHASH_NULLFREE(pCtx, pvh_status);
	SG_STAGING_NULLFREE(pCtx, pStaging);
}
void SG_cmd_util__dump_log(
	SG_context * pCtx, 
	SG_console_stream cs,
	SG_repo* pRepo, 
	const char* psz_hid_cs, 
	SG_vhash* pvhCleanPileOfBranches, 
	SG_bool bShowOnlyOpenBranchNames,
	SG_bool bShowFullComments)
{
	SG_history_result* pHistResult = NULL;
	SG_stringarray * psaHids = NULL;
	
	SG_STRINGARRAY__ALLOC(pCtx, &psaHids, 1);
	SG_ERR_CHECK(  SG_stringarray__add(pCtx, psaHids, psz_hid_cs)  );
	SG_history__get_revision_details(pCtx, pRepo, psaHids, NULL, &pHistResult);

    if (SG_context__err_equals(pCtx, SG_ERR_NOT_FOUND))
    {
		/* There's a branch that references a changeset that doesn't exist. Show what we can. */

		SG_vhash* pvhRefClosedBranches = NULL;
		SG_vhash* pvhRefBranchValues = NULL;

		SG_context__err_reset(pCtx);

		if (pvhCleanPileOfBranches)
		{
			SG_bool bHas = SG_FALSE;
			SG_ERR_CHECK(  SG_vhash__has(pCtx, pvhCleanPileOfBranches, "closed", &bHas)  );
			if (bHas)
				SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhCleanPileOfBranches, "closed", &pvhRefClosedBranches)  );

			SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhCleanPileOfBranches, "values", &pvhRefBranchValues)  );
		}

		SG_ERR_CHECK(  SG_console(pCtx, cs, "\n\t%8s:  %s\n", "revision", psz_hid_cs)  );
		SG_ERR_CHECK(  _dump_branch_name(pCtx, cs, psz_hid_cs, bShowOnlyOpenBranchNames, 
			pvhRefBranchValues, pvhRefClosedBranches)  );
		SG_ERR_CHECK(  SG_console(pCtx, cs, "\t%8s   %s\n", "", "(not present in repository)")  );
    }
    else
    {
		SG_ERR_CHECK_CURRENT;
        SG_ERR_CHECK(  SG_cmd_util__dump_history_results(pCtx, cs, pHistResult, pvhCleanPileOfBranches, bShowOnlyOpenBranchNames, bShowFullComments, SG_FALSE)  );
    }

fail:
	SG_HISTORY_RESULT_NULLFREE(pCtx, pHistResult);
	SG_STRINGARRAY_NULLFREE(pCtx, psaHids);
}
/**
 * The values for RENAME, MOVE, ATTRBITS, SYMLINKS, and SUBMODULES are collapsable.  (see below)
 * In the corresponding rbUnique's we only need to remember the set of unique values for the
 * field.  THESE ARE THE KEYS IN THE prbUnique.
 *
 * As a convenience, we associate a vector of entries with each key.  These form a many-to-one
 * thing so that we can report all of the entries that have this value.
 *
 * TODO since we should only process a cset once, we should not get any
 * TODO duplicates in the vector, but it might be possible.  i'm not going
 * TODO to worry about it now.  if this becomes a problem, consider doing
 * TODO a unique-insert into the vector -or- making the vector a sub-rbtree.
 *
 */
static void _update_1_rbUnique(SG_context * pCtx, SG_rbtree * prbUnique, const char * pszKey, SG_mrg_cset_entry * pMrgCSetEntry_Leaf_k)
{
	SG_vector * pVec_Allocated = NULL;
	SG_vector * pVec;
	SG_bool bFound;

	SG_ERR_CHECK(  SG_rbtree__find(pCtx,prbUnique,pszKey,&bFound,(void **)&pVec)  );
	if (!bFound)
	{
		SG_ERR_CHECK(  SG_VECTOR__ALLOC(pCtx,&pVec_Allocated,3)  );
		SG_ERR_CHECK(  SG_rbtree__add__with_assoc(pCtx,prbUnique,pszKey,pVec_Allocated)  );
		pVec = pVec_Allocated;
		pVec_Allocated = NULL;			// rbtree owns this now
	}

	SG_ERR_CHECK(  SG_vector__append(pCtx,pVec,pMrgCSetEntry_Leaf_k,NULL)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,"_update_1_rbUnique: [%s][%s]\n",
									   pszKey,
									   SG_string__sz(pMrgCSetEntry_Leaf_k->pMrgCSet->pStringCSetLabel))  );
#endif

	return;

fail:
	SG_VECTOR_NULLFREE(pCtx, pVec_Allocated);
}
/**
 * Insert/Replace a TNE ROW from the tne_L0 table in the wc.db.
 * 
 * The existing row (if it exists) is a copy of the TNE
 * as it existed in the current baseline.  This item
 * will be present in the future baseline, but it has
 * one or more changed fields.  So we want the TNE ROW
 * to be updated as we transition the tne_L0 table.
 *
 */
void sg_wc_tx__apply__insert_tne(SG_context * pCtx,
								 SG_wc_tx * pWcTx,
								 const SG_vhash * pvh)
{
#if TRACE_WC_TX_APPLY
	const char * pszRepoPath;

	SG_ERR_CHECK_RETURN(  SG_vhash__get__sz(pCtx, pvh, "src", &pszRepoPath)  );

	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   ("sg_wc_tx__apply__insert_tne: '%s'\n"),
							   pszRepoPath)  );
#else
	SG_UNUSED( pCtx );
	SG_UNUSED( pvh );
#endif

	SG_UNUSED( pWcTx );

	// we don't actually have anything here.
	// the journal record was more for the verbose log.
	// the actual work of updating the SQL will be done
	// in the parallel journal-stmt.

}
Exemplo n.º 8
0
void SG_dagfrag__foreach_member(SG_context * pCtx,
								SG_dagfrag * pFrag,
								SG_dagfrag__foreach_member_callback * pcb,
								void * pVoidCallerData)
{
	// we want to iterate over the START_ and INTERIOR_ MEMBERS in the CACHE.
	// we need to use the SORTED MEMBER CACHE so that ancestors are presented
	// before descendants.

	struct _fm_data fm_data;

	SG_NULLARGCHECK_RETURN(pFrag);
	SG_NULLARGCHECK_RETURN(pcb);

	if (!pFrag->m_pRB_GenerationSortedMemberCache)
		SG_ERR_CHECK_RETURN(  _my_create_generation_sorted_member_cache(pCtx,pFrag)  );

	fm_data.pFrag = pFrag;
	fm_data.pcb = pcb;
	fm_data.pVoidCallerData = pVoidCallerData;

	// we wrap their callback with our own so that we can munge the arguments
	// that they see.

#if TRACE_DAGFRAG && 0
	SG_ERR_CHECK_RETURN(  SG_console(pCtx, SG_CS_STDERR, "SORTED MEMBER CACHE:\r\n")  );
	SG_ERR_CHECK_RETURN(  SG_rbtree_debug__dump_keys_to_console(pCtx, pFrag->m_pRB_GenerationSortedMemberCache)  );
	SG_ERR_CHECK_RETURN(  SG_console__flush(pCtx, SG_CS_STDERR)  );
#endif

	SG_ERR_CHECK_RETURN(  SG_rbtree__foreach(pCtx,
											 pFrag->m_pRB_GenerationSortedMemberCache,
											 _sg_dagfrag__my_foreach_member_callback,
											 &fm_data)  );
}
Exemplo n.º 9
0
SG_error SG_context__err_to_console(SG_context* pCtx, SG_console_stream cs)
{
	SG_error err;
	SG_string* pErrStr = NULL;

	SG_ASSERT( pCtx );
//	SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS );

	if (pCtx->level > 0)		// when in an error-on-error (level > 0), there is NO error string.
		return SG_ERR_OK;		// so we don't need to do anything.

	// get the full error string about the error at the current level.

	err = SG_context__err_to_string(pCtx, &pErrStr);
	if (SG_IS_ERROR(err))		// an allocation/formatting error, just give up.
		return err;

	// write the error string/message to the console.  we push a new level
	// so that any problems converting the message to the user's locale or
	// writing to the console device don't trash the current error context.
	//
	// ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.***

	SG_context__push_level(pCtx);
	{
		SG_console(pCtx, cs, SG_string__sz(pErrStr));

		err = pCtx->errValues[pCtx->level];		// we return the error value of the conversion/writing.
	}
	SG_context__pop_level(pCtx);

	SG_STRING_NULLFREE(pCtx, pErrStr);

	return err;
}
void sg_wc_tx__apply__delete_issue(SG_context * pCtx,
								   SG_wc_tx * pWcTx,
								   const SG_vhash * pvh)
{
	SG_pathname * pPath = NULL;
	const char * pszRepoPathTempDir = NULL;

	// During the APPLY phase, our only task is to delete
	// the item's private tempdir, if it had one.  Only items
	// with file-edit conflicts will actually have one.

	SG_ERR_CHECK(  SG_vhash__check__sz(pCtx, pvh, "repopath_tempdir", &pszRepoPathTempDir)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "sg_wc_tx__apply__delete_issue: tempdir '%s'\n",
							   ((pszRepoPathTempDir) ? pszRepoPathTempDir : "(null)"))  );
#endif

	if (pszRepoPathTempDir)
	{
		SG_ERR_CHECK(  sg_wc_db__path__sz_repopath_to_absolute(pCtx, pWcTx->pDb, pszRepoPathTempDir, &pPath)  );
		// actually deleting the tempdir can fail for any number of reasons,
		// but that should not abort the COMMIT.  so we use _IGNORE() here
		// rather than _CHECK().
		SG_ERR_IGNORE(  SG_fsobj__rmdir_recursive__pathname(pCtx, pPath)  );
	}

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPath);
}
void sg_wc_db__gid__prepare_toggle_tmp_stmt(SG_context * pCtx,
											sg_wc_db * pDb,
											SG_uint64 uiAliasGid,
											SG_bool bIsTmp,
											sqlite3_stmt ** ppStmt)
{
	sqlite3_stmt * pStmt = NULL;

#if TRACE_WC_DB
	{
		SG_int_to_string_buffer bufui64;

		SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR, "sg_wc_db__gid__prepare_toggle_tmp_stmt: %s --> %c\n",
								   SG_uint64_to_sz(uiAliasGid, bufui64),
								   ((bIsTmp) ? 'T' : 'F'))  );
	}
#endif

	SG_ERR_CHECK(  sg_sqlite__prepare(pCtx, pDb->psql, &pStmt,
									  ("UPDATE tbl_gid SET tmp = ? WHERE alias_gid = ?"))  );
	SG_ERR_CHECK(  sg_sqlite__bind_int( pCtx, pStmt, 1, bIsTmp)  );
	SG_ERR_CHECK(  sg_sqlite__bind_int64(pCtx, pStmt, 2, uiAliasGid)  );

	*ppStmt = pStmt;
	return;

fail:
	SG_ERR_IGNORE(  sg_sqlite__finalize(pCtx, pStmt)  );
}
/**
 * During the revert-all setup, we add certain deleted items to the
 * kill-list (so that we'll delete the tbl_pc row for them) effectively
 * marking them clean -- and we don't insert them into the pMrgCSet
 * directly -- we let merge discover they are missing and decide what
 * to do.
 *
 * But if the merge-engine discovers the item and has different plans
 * for it, we cancel the predicted kill for it.
 *
 */
void sg_wc_tx__merge__remove_from_kill_list(SG_context * pCtx,
											SG_mrg * pMrg,
											const SG_uint64 uiAliasGid)
{
	SG_uint32 k, count;

	if (!pMrg->pVecRevertAllKillList)
		return;

	SG_ERR_CHECK(  SG_vector_i64__length(pCtx, pMrg->pVecRevertAllKillList, &count)  );
	for (k=0; k<count; k++)
	{
		SG_uint64 uiAliasGid_k;

		SG_ERR_CHECK(  SG_vector_i64__get(pCtx, pMrg->pVecRevertAllKillList, k, (SG_int64 *)&uiAliasGid_k)  );
		if (uiAliasGid_k == uiAliasGid)
		{
#if TRACE_WC_MERGE
			SG_int_to_string_buffer buf;
			SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
									   "Cancel kill-list for [0x%s]\n",
									   SG_uint64_to_sz__hex(uiAliasGid_k, buf))  );
#endif
			SG_ERR_CHECK(  SG_vector_i64__set(pCtx, pMrg->pVecRevertAllKillList, k, SG_WC_DB__ALIAS_GID__UNDEFINED)  );
		}
	}

fail:
	return;
}
/**
 * Prompt user for what to do on an individual item.
 *
 */
static void _do_prompt(SG_context * pCtx,
                       const char * pszPrompt,
                       const char * pszChoices,
                       char chDefault,
                       char * pchChoice)
{
    SG_string * pStringInput = NULL;

    while (1)
    {
        const char * pszInput;
        const char * p;

        SG_ERR_CHECK(  SG_console(pCtx, SG_CS_STDOUT, "%s: ", pszPrompt)  );
        SG_ERR_CHECK(  SG_console__readline_stdin(pCtx, &pStringInput)  );
        pszInput = SG_string__sz(pStringInput);
        while ((*pszInput==' ') || (*pszInput=='\t'))
            pszInput++;
        if ((*pszInput==0) || (*pszInput=='\r') || (*pszInput=='\n'))
        {
            *pchChoice = chDefault;
            break;
        }
        p = strchr(pszChoices, *pszInput);
        if (p)
        {
            *pchChoice = *p;
            break;
        }
        SG_STRING_NULLFREE(pCtx, pStringInput);
    }

fail:
    SG_STRING_NULLFREE(pCtx, pStringInput);
}
void sg_wc_db__gid__delete_all_tmp(SG_context * pCtx,
								   sg_wc_db * pDb)
{
	sqlite3_stmt * pStmt = NULL;

#if TRACE_WC_DB
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "sg_wc_db__gid__delete_all_tmp: had %d tmp gids.\n",
							   pDb->nrTmpGids)  );
#endif

	if (pDb->nrTmpGids == 0)
		return;

	SG_ERR_CHECK(  sg_sqlite__prepare(pCtx, pDb->psql, &pStmt,
									  ("DELETE FROM tbl_gid WHERE tmp != 0"))  );
	SG_ERR_CHECK(  sg_sqlite__step(pCtx, pStmt, SQLITE_DONE)  );
	SG_ERR_CHECK(  sg_sqlite__finalize(pCtx, pStmt)  );

	pDb->nrTmpGids = 0;

	return;

fail:
	SG_ERR_IGNORE(  sg_sqlite__finalize(pCtx, pStmt)  );
}
/**
 * remove the first item in the work-queue and return it for processing.
 *
 * You DO NOT own the returned sg_vv2status_od pointer.
 */
void sg_vv2__status__remove_first_from_work_queue(SG_context * pCtx,
												  sg_vv2status * pST,
												  SG_bool * pbFound,
												  sg_vv2status_od ** ppOD)
{
	const char * szKey;
	sg_vv2status_od * pOD;
	SG_bool bFound;

	SG_ERR_CHECK_RETURN(  SG_rbtree__iterator__first(pCtx,
													 NULL,pST->prbWorkQueue,
													 &bFound,
													 &szKey,(void **)&pOD)  );
	if (bFound)
	{
		SG_ERR_CHECK_RETURN(  SG_rbtree__remove(pCtx, pST->prbWorkQueue,szKey)  );

#if TRACE_VV2_STATUS
		SG_console(pCtx,SG_CS_STDERR,"TD_RMQUE %s (head)\n",szKey);
		SG_ERR_DISCARD;
#endif
	}

	*pbFound = bFound;
	*ppOD = ((bFound) ? pOD : NULL);
}
void sg_wc_db__gid__get_or_insert_alias_from_gid(SG_context * pCtx,
												 sg_wc_db * pDb,
												 const char * pszGid,
												 SG_uint64 * puiAliasGid)
{
	SG_bool bNotAlreadyPresent;
	
	sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, pszGid, puiAliasGid);
	bNotAlreadyPresent = SG_CONTEXT__HAS_ERR(pCtx);

	if (bNotAlreadyPresent)
	{
		SG_context__err_reset(pCtx);

		SG_ERR_CHECK(  sg_wc_db__gid__insert(pCtx, pDb, pszGid)  );
		SG_ERR_CHECK(  sg_wc_db__gid__get_alias_from_gid(pCtx, pDb, pszGid, puiAliasGid)  );
	}

#if TRACE_WC_GID
	{
		SG_int_to_string_buffer bufui64;

		SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
								   "GID: get_or_insert [%s] ==> %s [new %d]\n",
								   pszGid,
								   SG_uint64_to_sz(*puiAliasGid,bufui64),
								   bNotAlreadyPresent)  );
	}
#endif

fail:
	return;
}
/**
 * Create a per-tx temp-dir if we don't already have one.
 *
 */
void sg_wc_tx__create_session_temp_dir(SG_context * pCtx,
									   SG_wc_tx * pWcTx)
{
	char bufTidSession[SG_TID_MAX_BUFFER_LENGTH];
	SG_uint32 nrDigits = 10;

	if (pWcTx->pPathSessionTempDir)
		return;

	// pick a space in /tmp for exporting temporary copies of the files
	// so that internal and/or external tools can compare them.
	//
	// TODO 2012/05/02 Investigate the use of SG_workingdir__get_temp_path() (which
	// TODO            creates things in .sgdrawer rather than /tmp).
	// TODO            (see also sg_mrg__private_file_mrg.h)
	// TODO            See also sg_vv2__diff__create_session_temp_dir().

	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__USER_TEMP_DIRECTORY(pCtx, &pWcTx->pPathSessionTempDir)  );
	SG_ERR_CHECK(  SG_tid__generate2(pCtx, bufTidSession, sizeof(bufTidSession), nrDigits)  );
	SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, pWcTx->pPathSessionTempDir, bufTidSession)  );

	SG_ERR_TRY(  SG_fsobj__mkdir_recursive__pathname(pCtx, pWcTx->pPathSessionTempDir)  );
	SG_ERR_CATCH_IGNORE(  SG_ERR_DIR_ALREADY_EXISTS  );
	SG_ERR_CATCH_END;

#if 0 && defined(DEBUG)
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "CreateSessionTempDir: %s\n",
							   SG_pathname__sz(pWcTx->pPathSessionTempDir))  );
#endif

fail:
	return;
}
Exemplo n.º 18
0
void SG_getopt__print_invalid_option(SG_context* pCtx, SG_int32 code, const SG_getopt_option* option_table)
{
	const SG_getopt_option* pOpt;

	SG_getopt__get_option_from_code(code, option_table, &pOpt);

	if (pOpt)
	{
		if (pOpt->optch <= 255)
			SG_console(pCtx, SG_CS_STDERR, "-%c [--%s]\n", pOpt->optch, pOpt->pStringName);
		else
			SG_console(pCtx, SG_CS_STDERR, "--%s\n", pOpt->pStringName);
	} 
	else
		SG_console(pCtx, SG_CS_STDERR, "-%c\n", code);
}
Exemplo n.º 19
0
static void _resolve__fix__run_external_file_merge_1(SG_context * pCtx,
													 struct _resolve_data * pData,
													 _resolve__external_tool * pET,
													 _resolve__step_pathnames * pStepPathnames,
													 SG_string * pStrRepoPath,
													 SG_bool * pbMergedText)
{
	SG_exec_argvec * pArgVec = NULL;
	SG_exit_status exitStatus;

	SG_UNUSED( pData );

#if 0 && defined(DEBUG)
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   ("RESOLVE File Merge: %s\n"
								"          Mine: %s\n"
								"         Other: %s\n"
								"      Ancestor: %s\n"
								"        Result: %s\n"),
							   SG_string__sz(pStrRepoPath),
							   SG_pathname__sz(pStepPathnames->pPath_Mine),
							   SG_pathname__sz(pStepPathnames->pPath_Other),
							   SG_pathname__sz(pStepPathnames->pPath_Ancestor),
							   SG_pathname__sz(pStepPathnames->pPath_Result))  );
#endif


	SG_ERR_CHECK(  SG_exec_argvec__alloc(pCtx, &pArgVec)  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-r")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Result))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t1")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "Mine")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t2")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_string__sz(pStrRepoPath))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "-t3")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, "Other")  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Mine))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Ancestor))  );
	SG_ERR_CHECK(  SG_exec_argvec__append__sz(pCtx, pArgVec, SG_pathname__sz(pStepPathnames->pPath_Other))  );

	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDOUT, "RESOLVE: Preparing to launch external merge tool: %s\n", pET->pszName)  );
	SG_ERR_CHECK(  SG_exec__exec_sync__files(pCtx, pET->pszExe, pArgVec, NULL, NULL, NULL, &exitStatus)  );
	*pbMergedText = (exitStatus == 0);

fail:
	SG_EXEC_ARGVEC_NULLFREE(pCtx, pArgVec);
}
/**
 * Export the contents of the given file entry (which reflects a specific version)
 * into a temp file so that an external tool can use it.
 *
 * You own the returned pathname and the file on disk.
 */
void _sg_mrg__export_to_temp_file(SG_context * pCtx, SG_mrg * pMrg,
								  const char * pszHidBlob,
								  const SG_pathname * pPathTempFile)
{
	SG_file * pFile = NULL;
	SG_bool bExists;

	SG_ERR_CHECK(  SG_fsobj__exists__pathname(pCtx,pPathTempFile,&bExists,NULL,NULL)  );
	if (bExists)
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Skipping export of [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile))  );
#endif
	}
	else
	{
#if TRACE_WC_MERGE
		SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,
								   "Exporting          [blob %s] to [%s]\n",pszHidBlob,SG_pathname__sz(pPathTempFile))  );
#endif

		// Ideally, when we create this TEMP file it should be read-only.
		// Afterall, it does represent a historical version of the file and
		// it should only be used as INPUT to whatever merge tool the user
		// has configured.  So it should be read-only.  This might allow
		// a GUI merge tool to show locks/whatever and/or prevent accidental
		// editing of these files.
		//
		// However, this can cause an "Access is Denied" error on Windows
		// when we get ready to delete the contents of the TEMP directory.
		// We'll deal with that there rather than here.

		SG_ERR_CHECK(  SG_file__open__pathname(pCtx,pPathTempFile,SG_FILE_WRONLY|SG_FILE_CREATE_NEW,0400,&pFile)  );
		SG_ERR_CHECK(  SG_repo__fetch_blob_into_file(pCtx, pMrg->pWcTx->pDb->pRepo, pszHidBlob,pFile,NULL)  );
		SG_FILE_NULLCLOSE(pCtx,pFile);
	}

	return;

fail:
	if (pFile)			// only if **WE** created the file, do we try to delete it on error.
	{
		SG_FILE_NULLCLOSE(pCtx,pFile);
		SG_ERR_IGNORE(  SG_fsobj__remove__pathname(pCtx,pPathTempFile)  );
	}
}
/**
 * Dump the commitFlags for the entire tree.
 *
 */
void sg_wc_tx__commit__dump_marks(SG_context * pCtx,
								  SG_wc_tx * pWcTx,
								  const char * pszLabel)
{
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "CommitDump: %s\n",
							   pszLabel)  );

	SG_ERR_CHECK_RETURN(  _dump_marks__lvi(pCtx, pWcTx, pWcTx->pLiveViewItem_Root, 0, "           ", SG_TRUE)  );
}
void sg_wc_db__debug__tne_row__print(SG_context * pCtx, sg_wc_db__tne_row * pTneRow)
{
	SG_int_to_string_buffer bufui64_a;
	SG_int_to_string_buffer bufui64_b;
		
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "sg_wc_db:tne_row: [gid %s][par %s][hid %s] %s\n",
							   SG_uint64_to_sz(pTneRow->p_s->uiAliasGid,       bufui64_a),
							   SG_uint64_to_sz(pTneRow->p_s->uiAliasGidParent, bufui64_b),
							   pTneRow->p_d->pszHid,
							   pTneRow->p_s->pszEntryname)  );
}
void sg_wc_tx__apply__move_rename(SG_context * pCtx,
								  SG_wc_tx * pWcTx,
								  const SG_vhash * pvh)
{
	SG_bool bAfterTheFact;
	SG_bool bUseIntermediate;
	SG_bool bSrcIsSparse;
	const char * pszRepoPath_Src;
	const char * pszRepoPath_Dest;
	SG_pathname * pPath_Src = NULL;
	SG_pathname * pPath_Dest = NULL;
	SG_pathname * pPath_Temp = NULL;

	SG_ERR_CHECK(  SG_vhash__get__bool(pCtx, pvh, "after_the_fact", &bAfterTheFact)  );
	SG_ERR_CHECK(  SG_vhash__get__bool(pCtx, pvh, "use_intermediate", &bUseIntermediate)  );
	SG_ERR_CHECK(  SG_vhash__get__bool(pCtx, pvh, "src_sparse", &bSrcIsSparse)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvh, "src", &pszRepoPath_Src)  );
	SG_ERR_CHECK(  SG_vhash__get__sz(pCtx, pvh, "dest", &pszRepoPath_Dest)  );

#if TRACE_WC_TX_APPLY
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   ("sg_wc_tx__apply__move_rename: [after-the-fact %d][use-intermediate %d][src-sparse %d] '%s' --> '%s'\n"),
							   bAfterTheFact, bUseIntermediate, bSrcIsSparse,
							   pszRepoPath_Src,
							   pszRepoPath_Dest)  );
#endif

	if (bAfterTheFact || bSrcIsSparse)		// user already did the move/rename.
		return;

	SG_ERR_CHECK(  sg_wc_db__path__sz_repopath_to_absolute(pCtx, pWcTx->pDb, pszRepoPath_Src,  &pPath_Src )  );
	SG_ERR_CHECK(  sg_wc_db__path__sz_repopath_to_absolute(pCtx, pWcTx->pDb, pszRepoPath_Dest, &pPath_Dest)  );

	if (bUseIntermediate)
	{
		// need to use a temp file because of transient
		// collisions ('vv rename foo FOO' on Windows).
		SG_ERR_CHECK(  sg_wc_db__path__get_unique_temp_path(pCtx, pWcTx->pDb, &pPath_Temp)  );
		SG_ERR_CHECK(  SG_fsobj__move__pathname_pathname(pCtx, pPath_Src,  pPath_Temp)  );
		SG_ERR_CHECK(  SG_fsobj__move__pathname_pathname(pCtx, pPath_Temp, pPath_Dest)  );
	}
	else
	{
		SG_ERR_CHECK(  SG_fsobj__move__pathname_pathname(pCtx, pPath_Src, pPath_Dest)  );
	}

fail:
	SG_PATHNAME_NULLFREE(pCtx, pPath_Src);
	SG_PATHNAME_NULLFREE(pCtx, pPath_Dest);
	SG_PATHNAME_NULLFREE(pCtx, pPath_Temp);
}
void sg_wc_tx__merge__determine_target_cset(SG_context * pCtx,
											SG_mrg * pMrg)
{
	SG_ERR_CHECK(  _merge__compute_target_hid(pCtx, pMrg)  );

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "Merge: target   (%s).\n",
							   pMrg->pszHidTarget)  );
#endif

fail:
	return;
}
static void _dump_branch_name(
	SG_context* pCtx,
	SG_console_stream cs,
	const char* pszRefHid, 
	SG_bool bShowOnlyOpenBranchNames,
	const SG_vhash* pvhRefBranchValues,
	const SG_vhash* pvhRefClosedBranches)
{
	SG_vhash* pvhRefBranchNames = NULL;

	if (pvhRefBranchValues)
	{
		SG_bool b_has = SG_FALSE;

		SG_ERR_CHECK(  SG_vhash__has(pCtx, pvhRefBranchValues, pszRefHid, &b_has)  );
		if (b_has)
		{
			SG_ERR_CHECK(  SG_vhash__get__vhash(pCtx, pvhRefBranchValues, pszRefHid, &pvhRefBranchNames)  );
		}
	}

	if (pvhRefBranchNames)
	{
		SG_uint32 count_branch_names = 0;
		SG_uint32 i;

		SG_ERR_CHECK(  SG_vhash__count(pCtx, pvhRefBranchNames, &count_branch_names)  );
		for (i=0; i<count_branch_names; i++)
		{
			const char* psz_branch_name = NULL;
			SG_bool bClosed = SG_FALSE;

			SG_ERR_CHECK(  SG_vhash__get_nth_pair(pCtx, pvhRefBranchNames, i, &psz_branch_name, NULL)  );

			if (pvhRefClosedBranches)
				SG_ERR_CHECK(  SG_vhash__has(pCtx, pvhRefClosedBranches, psz_branch_name, &bClosed)  );

			if ( !bShowOnlyOpenBranchNames || (bShowOnlyOpenBranchNames && !bClosed) )
			{
				SG_ERR_CHECK(  SG_console(pCtx, cs, "\t%8s:  %s%s\n", "branch", 
					psz_branch_name, bClosed ? " (closed)" : "")  );
			}
		}
	}

fail:
	;
}
void sg_wc_tx__fake_merge__revert_all__determine_target_cset(SG_context * pCtx,
															 SG_mrg * pMrg)
{
	SG_ERR_CHECK(  SG_strdup(pCtx, pMrg->pszHid_StartingBaseline, &pMrg->pszHidTarget)  );

	// Don't worry about pMrg->pvhPile; it is just a cache and loaded as needed.

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "FakeMergeRevertAll: target   (%s).\n",
							   pMrg->pszHidTarget)  );
#endif

fail:
	return;
}
Exemplo n.º 27
0
void SG_dagfrag_debug__dump__console(SG_context* pCtx,
									 SG_dagfrag* pFrag,
									 const char* szLabel,
									 SG_uint32 indent,
									 SG_console_stream cs)
{
	SG_string* pString;
	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pString)  );
	SG_ERR_CHECK(  SG_dagfrag_debug__dump(pCtx, pFrag, szLabel, indent, pString)  );
	SG_ERR_CHECK(  SG_console(pCtx, cs, SG_string__sz(pString))  );
	SG_ERR_CHECK(  SG_console__flush(pCtx, cs)  );

	// fall through
fail:
	SG_STRING_NULLFREE(pCtx, pString);
}
/**
 * The values for RENAME, MOVE, ATTRBITS, SYMLINKS, and SUBMODULES are collapsable.  (see below)
 * In the corresponding rbUnique's we only need to remember the set of unique values for the
 * field.  THESE ARE THE KEYS IN THE prbUnique.
 *
 * As a convenience, we associate a vector of entries with each key.  These form a many-to-one
 * thing so that we can report all of the entries that have this value.
 *
 * Here we carry-forward the values from a sub-merge to the outer-merge by coping the keys
 * in the source-rbtree and insert in the destination-rbtree.
 *
 * NOTE: the term sub-merge here refers to the steps within an n-way merge;
 * it DOES NOT refer to a submodule.
 */
static void _carry_forward_unique_values(SG_context * pCtx,
										 SG_rbtree * prbDest,
										 SG_rbtree * prbSrc)
{
	SG_rbtree_iterator * pIter = NULL;
	SG_vector * pVec_Allocated = NULL;
	const char * pszKey;
	SG_vector * pVec_Src;
	SG_vector * pVec_Dest;
	SG_uint32 j, nr;
	SG_bool bFound;


	SG_ERR_CHECK(  SG_rbtree__iterator__first(pCtx,&pIter,prbSrc,&bFound,&pszKey,(void **)&pVec_Src)  );
	while (bFound)
	{
		SG_ERR_CHECK(  SG_rbtree__find(pCtx,prbDest,pszKey,&bFound,(void **)&pVec_Dest)  );
		if (!bFound)
		{
			SG_ERR_CHECK(  SG_VECTOR__ALLOC(pCtx,&pVec_Allocated,3)  );
			SG_ERR_CHECK(  SG_rbtree__add__with_assoc(pCtx,prbDest,pszKey,pVec_Allocated)  );
			pVec_Dest = pVec_Allocated;
			pVec_Allocated = NULL;			// rbtree owns this now
		}

		SG_ERR_CHECK(  SG_vector__length(pCtx,pVec_Src,&nr)  );
		for (j=0; j<nr; j++)
		{
			SG_mrg_cset_entry * pMrgCSetEntry_x;

			SG_ERR_CHECK(  SG_vector__get(pCtx,pVec_Src,j,(void **)&pMrgCSetEntry_x)  );
			SG_ERR_CHECK(  SG_vector__append(pCtx,pVec_Dest,pMrgCSetEntry_x,NULL)  );

#if TRACE_WC_MERGE
			SG_ERR_IGNORE(  SG_console(pCtx,SG_CS_STDERR,"_carry_forward_unique_value: [%s][%s]\n",
									   pszKey,
									   SG_string__sz(pMrgCSetEntry_x->pMrgCSet->pStringCSetLabel))  );
#endif
		}

		SG_ERR_CHECK(  SG_rbtree__iterator__next(pCtx,pIter,&bFound,&pszKey,NULL)  );
	}

fail:
	SG_RBTREE_ITERATOR_NULLFREE(pCtx,pIter);
}
/**
 * This routine is used by UPDATE to fake a MERGE; that is, to do
 * a one-legged merge.  This routine must do set the same fields
 * in pMrg that the above routine does.
 *
 * I've isolated the effects here because UPDATE has already done
 * most of the homework/validation and we don't need to step thru
 * the stuff again here.
 *
 */
void sg_wc_tx__fake_merge__update__determine_target_cset(SG_context * pCtx,
														 SG_mrg * pMrg,
														 const char * pszHidTarget)
{
	SG_ERR_CHECK(  SG_strdup(pCtx, pszHidTarget, &pMrg->pszHidTarget)  );

	// Don't worry about pMrg->pvhPile; it is just a cache and loaded as needed.

#if TRACE_WC_MERGE
	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "FakeMergeUpdate: target   (%s).\n",
							   pMrg->pszHidTarget)  );
#endif

fail:
	return;
}
static void _dump_marks__lvi(SG_context * pCtx,
							 SG_wc_tx * pWcTx,
							 sg_wc_liveview_item * pLVI,
							 SG_uint32 indent,
							 const char * pszPrefix,
							 SG_bool bDive)
{
	SG_int_to_string_buffer bufui64;

	SG_ERR_IGNORE(  SG_console(pCtx, SG_CS_STDERR,
							   "%*c %02x 0x%s %s %s\n",
							   indent, ' ',
							   pLVI->commitFlags,
							   SG_uint64_to_sz__hex((SG_uint64)pLVI->statusFlags_commit,bufui64),
							   pszPrefix,
							   SG_string__sz(pLVI->pStringEntryname))  );

	if ((bDive) && (pLVI->tneType == SG_TREENODEENTRY_TYPE_DIRECTORY))
	{
		sg_wc_liveview_dir * pLVD;		// we do not own this
		struct dump_data dump_data;

		dump_data.pWcTx = pWcTx;
		dump_data.indent = indent + 4;

		SG_ERR_CHECK(  sg_wc_tx__liveview__fetch_dir(pCtx, pWcTx, pLVI, &pLVD)  );
		if (pLVD->prb64LiveViewItems)
		{
			SG_ERR_CHECK(  sg_wc_liveview_dir__foreach(pCtx,
													   pLVD,
													   _dump_marks__dir__current__cb,
													   &dump_data)  );
		}
		if (pLVD->prb64MovedOutItems)
		{
			SG_ERR_CHECK(  sg_wc_liveview_dir__foreach_moved_out(pCtx,
																 pLVD,
																 _dump_marks__dir__moved_out__cb,
																 &dump_data)  );
		}
	}

fail:
	return;
}