void SG_server__get_dagnode_info( SG_context* pCtx, SG_repo* pRepo, SG_vhash* pvhRequest, SG_varray** ppvaInfo) { char bufDagnum[SG_DAGNUM__BUF_MAX__DEC]; SG_vhash* pvhRefVersionControlHids = NULL; SG_varray* pvaHids = NULL; SG_stringarray* psaHids = NULL; const char* const* paszHids = NULL; SG_uint32 countHids = 0; SG_ERR_CHECK( SG_dagnum__to_sz__decimal(pCtx, SG_DAGNUM__VERSION_CONTROL, bufDagnum, sizeof(bufDagnum)) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvhRequest, bufDagnum, &pvhRefVersionControlHids) ); // Ugh. Is vhash->varray->stringarray->char** the best option? SG_ERR_CHECK( SG_vhash__get_keys(pCtx, pvhRefVersionControlHids, &pvaHids) ); SG_ERR_CHECK( SG_varray__to_stringarray(pCtx, pvaHids, &psaHids) ); SG_ERR_CHECK( SG_stringarray__sz_array_and_count(pCtx, psaHids, &paszHids, &countHids) ); SG_ERR_CHECK( SG_history__query(pCtx, NULL, pRepo, 0, NULL, paszHids, countHids, NULL, NULL, 0, 0, 0, SG_FALSE, SG_FALSE, ppvaInfo) ); /* fall through */ fail: SG_VARRAY_NULLFREE(pCtx, pvaHids); SG_STRINGARRAY_NULLFREE(pCtx, psaHids); }
void do_cmd_merge_preview(SG_context * pCtx, SG_option_state * pOptSt) { SG_repo * pRepo = NULL; SG_uint32 countRevSpecs = 0; SG_stringarray * psaRevSpecs = NULL; const char * const * ppszRevSpecs = NULL; SG_stringarray * psaNewChangesets = NULL; const char * const * ppszNewChangesets = NULL; SG_uint32 countNewChangesets = 0; char * pszHidBaseline = NULL; char * pszHidMergeTarget = NULL; SG_dagquery_relationship relationship; SG_vhash * pvhPileOfCleanBranches = NULL; SG_uint32 i = 0; countRevSpecs = 0; if (pOptSt->pRevSpec) { SG_ERR_CHECK( SG_rev_spec__count(pCtx, pOptSt->pRevSpec, &countRevSpecs) ); if(countRevSpecs>2) SG_ERR_THROW(SG_ERR_USAGE); } if(pOptSt->psz_repo!=NULL) { if(countRevSpecs==2) { SG_ERR_CHECK( SG_REPO__OPEN_REPO_INSTANCE(pCtx, pOptSt->psz_repo, &pRepo) ); SG_ERR_CHECK( SG_rev_spec__get_all__repo(pCtx, pRepo, pOptSt->pRevSpec, SG_FALSE, &psaRevSpecs, NULL) ); SG_ERR_CHECK( SG_stringarray__sz_array(pCtx, psaRevSpecs, &ppszRevSpecs) ); SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[0], &pszHidBaseline) ); SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[1], &pszHidMergeTarget) ); SG_STRINGARRAY_NULLFREE(pCtx, psaRevSpecs); } else { SG_ERR_THROW2(SG_ERR_USAGE, (pCtx, "When using the --repo option, you must provide both the BASELINE-REVSPEC and the OTHER-REVSPEC.")); } } else { SG_ERR_CHECK( SG_cmd_util__get_repo_from_cwd(pCtx, &pRepo, NULL) ); if(countRevSpecs==2) { SG_ERR_CHECK( SG_rev_spec__get_all__repo(pCtx, pRepo, pOptSt->pRevSpec, SG_FALSE, &psaRevSpecs, NULL) ); SG_ERR_CHECK( SG_stringarray__sz_array(pCtx, psaRevSpecs, &ppszRevSpecs) ); SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[0], &pszHidBaseline) ); SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[1], &pszHidMergeTarget) ); SG_STRINGARRAY_NULLFREE(pCtx, psaRevSpecs); } else { SG_uint32 countBaselines = 0; SG_ERR_CHECK( SG_wc__get_wc_parents__stringarray(pCtx, NULL, &psaRevSpecs) ); SG_ERR_CHECK( SG_stringarray__sz_array_and_count(pCtx, psaRevSpecs, &ppszRevSpecs, &countBaselines) ); SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[0], &pszHidBaseline) ); if(countBaselines==2) { SG_ERR_CHECK( SG_STRDUP(pCtx, ppszRevSpecs[1], &pszHidMergeTarget) ); } else { SG_wc_merge_args merge_args; merge_args.pRevSpec = pOptSt->pRevSpec; merge_args.bNoAutoMergeFiles = SG_TRUE; // doesn't matter merge_args.bComplainIfBaselineNotLeaf = SG_FALSE; // doesn't matter SG_ERR_CHECK( SG_wc__merge__compute_preview_target(pCtx, NULL, &merge_args, &pszHidMergeTarget) ); } SG_STRINGARRAY_NULLFREE(pCtx, psaRevSpecs); } } SG_ERR_CHECK( SG_dagquery__how_are_dagnodes_related(pCtx, pRepo, SG_DAGNUM__VERSION_CONTROL, pszHidMergeTarget, pszHidBaseline, SG_FALSE, SG_FALSE, &relationship) ); if(relationship==SG_DAGQUERY_RELATIONSHIP__ANCESTOR || relationship==SG_DAGQUERY_RELATIONSHIP__SAME) { SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDOUT, "The baseline already includes the merge target. No merge is needed.\n") ); } else { SG_ERR_CHECK( SG_dagquery__find_new_since_common(pCtx, pRepo, SG_DAGNUM__VERSION_CONTROL, pszHidBaseline, pszHidMergeTarget, &psaNewChangesets) ); SG_ERR_CHECK( SG_stringarray__sz_array_and_count(pCtx, psaNewChangesets, &ppszNewChangesets, &countNewChangesets) ); SG_ERR_CHECK( SG_vc_branches__cleanup(pCtx, pRepo, &pvhPileOfCleanBranches) ); for(i=0; i<countNewChangesets; ++i) { SG_ERR_CHECK( SG_cmd_util__dump_log(pCtx, SG_CS_STDOUT, pRepo, ppszNewChangesets[i], pvhPileOfCleanBranches, SG_TRUE, SG_FALSE) ); } if(relationship==SG_DAGQUERY_RELATIONSHIP__DESCENDANT) { SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDOUT, "\nFast-Forward Merge to '%s' brings in %i changeset%s.\n", pszHidMergeTarget, countNewChangesets, ((countNewChangesets==1)?"":"s")) ); } else { SG_ERR_CHECK( SG_console(pCtx, SG_CS_STDOUT, "\nMerge with '%s' brings in %i changeset%s.\n", pszHidMergeTarget, countNewChangesets, ((countNewChangesets==1)?"":"s")) ); } } SG_VHASH_NULLFREE(pCtx, pvhPileOfCleanBranches); SG_STRINGARRAY_NULLFREE(pCtx, psaNewChangesets); SG_NULLFREE(pCtx, pszHidBaseline); SG_NULLFREE(pCtx, pszHidMergeTarget); SG_REPO_NULLFREE(pCtx, pRepo); return; fail: SG_REPO_NULLFREE(pCtx, pRepo); SG_STRINGARRAY_NULLFREE(pCtx, psaNewChangesets); SG_STRINGARRAY_NULLFREE(pCtx, psaRevSpecs); SG_NULLFREE(pCtx, pszHidBaseline); SG_NULLFREE(pCtx, pszHidMergeTarget); SG_VHASH_NULLFREE(pCtx, pvhPileOfCleanBranches); }
void SG_dagquery__highest_revno_common_ancestor( SG_context * pCtx, SG_repo * pRepo, SG_uint64 dagnum, const SG_stringarray * pInputNodeHids, char ** ppOutputNodeHid ) { const char * const * paszInputNodeHids = NULL; SG_uint32 countInputNodes = 0; SG_repo_fetch_dagnodes_handle * pDagnodeFetcher = NULL; _hrca_work_queue_t workQueue = {NULL, 0, 0, NULL}; SG_uint32 i; SG_dagnode * pDagnode = NULL; const char * pszHidRef = NULL; SG_bitvector * pIsAncestorOf = NULL; SG_uint32 countIsAncestorOf = 0; SG_ASSERT(pCtx!=NULL); SG_NULLARGCHECK(pRepo); SG_NULLARGCHECK(pInputNodeHids); SG_ERR_CHECK( SG_stringarray__sz_array_and_count(pCtx, pInputNodeHids, &paszInputNodeHids, &countInputNodes) ); SG_ARGCHECK(countInputNodes>0, pInputNodeHids); SG_NULLARGCHECK(ppOutputNodeHid); SG_ERR_CHECK( SG_repo__fetch_dagnodes__begin(pCtx, pRepo, dagnum, &pDagnodeFetcher) ); SG_ERR_CHECK( SG_allocN(pCtx, _HRCA_WORK_QUEUE_INIT_LENGTH, workQueue.p) ); workQueue.allocatedLength = _HRCA_WORK_QUEUE_INIT_LENGTH; SG_ERR_CHECK( SG_RBTREE__ALLOC(pCtx, &workQueue.pRevnoCache) ); SG_ERR_CHECK( SG_BITVECTOR__ALLOC(pCtx, &pIsAncestorOf, countInputNodes) ); for(i=0; i<countInputNodes; ++i) { SG_ERR_CHECK( SG_bitvector__zero(pCtx, pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__set_bit(pCtx, pIsAncestorOf, i, SG_TRUE) ); SG_ERR_CHECK( _hrca_work_queue__insert(pCtx, &workQueue, paszInputNodeHids[i], pRepo, pDagnodeFetcher, pIsAncestorOf) ); } SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); SG_ERR_CHECK( _hrca_work_queue__pop(pCtx, &workQueue, &pDagnode, &pszHidRef, &pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__count_set_bits(pCtx, pIsAncestorOf, &countIsAncestorOf) ); while(countIsAncestorOf < countInputNodes) { SG_uint32 count_parents = 0; const char** parents = NULL; SG_ERR_CHECK( SG_dagnode__get_parents__ref(pCtx, pDagnode, &count_parents, &parents) ); for(i=0; i<count_parents; ++i) SG_ERR_CHECK( _hrca_work_queue__insert(pCtx, &workQueue, parents[i], pRepo, pDagnodeFetcher, pIsAncestorOf) ); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); SG_ERR_CHECK( _hrca_work_queue__pop(pCtx, &workQueue, &pDagnode, &pszHidRef, &pIsAncestorOf) ); SG_ERR_CHECK( SG_bitvector__count_set_bits(pCtx, pIsAncestorOf, &countIsAncestorOf) ); } SG_ERR_CHECK( SG_strdup(pCtx, pszHidRef, ppOutputNodeHid) ); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); for(i=0; i<workQueue.length; ++i) { SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_BITVECTOR_NULLFREE(pCtx, workQueue.p[i].pIsAncestorOf); } SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); SG_ERR_CHECK( SG_repo__fetch_dagnodes__end(pCtx, pRepo, &pDagnodeFetcher) ); return; fail: for(i=0; i<workQueue.length; ++i) { SG_DAGNODE_NULLFREE(pCtx, workQueue.p[i].pDagnode); SG_BITVECTOR_NULLFREE(pCtx, workQueue.p[i].pIsAncestorOf); } SG_NULLFREE(pCtx, workQueue.p); SG_RBTREE_NULLFREE(pCtx, workQueue.pRevnoCache); SG_DAGNODE_NULLFREE(pCtx, pDagnode); SG_BITVECTOR_NULLFREE(pCtx, pIsAncestorOf); if(pDagnodeFetcher!=NULL) { SG_ERR_IGNORE( SG_repo__fetch_dagnodes__end(pCtx, pRepo, &pDagnodeFetcher) ); } }