static void do_one_template( SG_context* pCtx, SG_repo* pRepo, SG_uint32 iDagNum, SG_audit* pq, unsigned char* pjson ) { SG_vhash* pvh_template = NULL; SG_changeset* pcs = NULL; SG_dagnode* pdn = NULL; SG_zingtx* ptx = NULL; SG_string* pstr = NULL; // now the main dag SG_ERR_CHECK( SG_zing__begin_tx(pCtx, pRepo, iDagNum, pq->who_szUserId, NULL, &ptx) ); SG_ERR_CHECK( my_strip_comments(pCtx, (char*) pjson, &pstr) ); SG_ERR_CHECK( SG_vhash__alloc__from_json(pCtx, &pvh_template, SG_string__sz(pstr))); SG_ERR_CHECK( SG_zingtx__store_template(pCtx, ptx, &pvh_template) ); SG_ERR_CHECK( SG_zing__commit_tx(pCtx, pq->when_int64, &ptx, &pcs, &pdn, NULL) ); SG_STRING_NULLFREE(pCtx, pstr); SG_CHANGESET_NULLFREE(pCtx, pcs); SG_DAGNODE_NULLFREE(pCtx, pdn); // fall thru fail: SG_STRING_NULLFREE(pCtx, pstr); SG_CHANGESET_NULLFREE(pCtx, pcs); SG_DAGNODE_NULLFREE(pCtx, pdn); }
// TODO consider the possible perf benefits of changing this routine // to accept lots of changeset ids instead of just one, so it // can handle them all at once. void SG_treendx__update__multiple( SG_context* pCtx, SG_treendx* pTreeNdx, SG_stringarray* psa ) { SG_changeset* pcs = NULL; sqlite3_stmt* pStmt = NULL; SG_vhash* pvh_treepaths = NULL; SG_uint32 count_treepaths = 0; SG_uint32 count_changesets = 0; SG_uint32 ics = 0; SG_NULLARGCHECK_RETURN(psa); SG_NULLARGCHECK_RETURN(pTreeNdx); SG_ERR_CHECK( SG_stringarray__count(pCtx, psa, &count_changesets) ); SG_ERR_CHECK( sg_sqlite__exec__va(pCtx, pTreeNdx->psql, "BEGIN TRANSACTION; ") ); SG_ERR_CHECK( sg_sqlite__prepare(pCtx, pTreeNdx->psql, &pStmt, "INSERT OR IGNORE INTO treendx (gid, strpath) VALUES (?, ?)") ); for (ics=0; ics<count_changesets; ics++) { const char* psz_hid = NULL; SG_uint32 i = 0; SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, psa, ics, &psz_hid) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pTreeNdx->pRepo, psz_hid, &pcs) ); SG_ERR_CHECK( SG_changeset__get_treepaths(pCtx, pcs, &pvh_treepaths) ); if (pvh_treepaths) { SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_treepaths, &count_treepaths) ); for (i=0; i<count_treepaths; i++) { const char* psz_gid = NULL; const SG_variant* pv = NULL; const char* psz_path = NULL; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_treepaths, i, &psz_gid, &pv) ); SG_ERR_CHECK( SG_variant__get__sz(pCtx, pv, &psz_path) ); SG_ERR_CHECK( sg_sqlite__reset(pCtx, pStmt) ); SG_ERR_CHECK( sg_sqlite__clear_bindings(pCtx, pStmt) ); SG_ERR_CHECK( sg_sqlite__bind_text(pCtx, pStmt, 1, psz_gid) ); SG_ERR_CHECK( sg_sqlite__bind_text(pCtx, pStmt, 2, psz_path) ); SG_ERR_CHECK( sg_sqlite__step(pCtx, pStmt, SQLITE_DONE) ); } } SG_CHANGESET_NULLFREE(pCtx, pcs); } SG_ERR_CHECK( sg_sqlite__nullfinalize(pCtx, &pStmt) ); SG_ERR_CHECK( sg_sqlite__exec__va(pCtx, pTreeNdx->psql, "COMMIT TRANSACTION; ") ); fail: SG_CHANGESET_NULLFREE(pCtx, pcs); }
void SG_treendx__get_path_in_dagnode(SG_context* pCtx, SG_treendx* pTreeNdx, const char* psz_search_item_gid, const char* psz_changeset, SG_treenode_entry ** ppTreeNodeEntry) { SG_rbtree_iterator * rb_it = NULL; const char * pPath = NULL; SG_changeset * pChangeset = NULL; SG_stringarray * pPaths = NULL; const char* pszHidTreeNode = NULL; SG_treenode * pTreenodeRoot = NULL; char* pszReturnedGID = NULL; SG_uint32 i = 0; SG_uint32 count = 0; SG_ERR_CHECK_RETURN( SG_gid__argcheck(pCtx, psz_search_item_gid) ); SG_ERR_CHECK( SG_treendx__get_all_paths(pCtx, pTreeNdx, psz_search_item_gid, &pPaths) ); *ppTreeNodeEntry = NULL; SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pTreeNdx->pRepo, psz_changeset, &pChangeset) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pChangeset, &pszHidTreeNode) ); SG_ERR_CHECK( SG_treenode__load_from_repo(pCtx, pTreeNdx->pRepo, pszHidTreeNode, &pTreenodeRoot) ); SG_ERR_CHECK( SG_stringarray__count(pCtx, pPaths, &count ) ); for (i = 0; i < count; i++) { SG_ERR_CHECK( SG_stringarray__get_nth(pCtx, pPaths, i, &pPath) ); SG_ERR_CHECK( SG_treenode__find_treenodeentry_by_path(pCtx, pTreeNdx->pRepo, pTreenodeRoot, pPath, &pszReturnedGID, ppTreeNodeEntry) ); if (*ppTreeNodeEntry != NULL && strcmp(pszReturnedGID, psz_search_item_gid) == 0) { break; } else if (*ppTreeNodeEntry != NULL) { SG_TREENODE_ENTRY_NULLFREE(pCtx, *ppTreeNodeEntry); *ppTreeNodeEntry = NULL; //It's not the right GID, even though it's in the right spot. } } SG_NULLFREE(pCtx, pszReturnedGID); SG_CHANGESET_NULLFREE(pCtx, pChangeset); SG_TREENODE_NULLFREE(pCtx, pTreenodeRoot); SG_STRINGARRAY_NULLFREE(pCtx, pPaths); SG_RBTREE_ITERATOR_NULLFREE(pCtx, rb_it); return; fail: SG_NULLFREE(pCtx, pszReturnedGID); SG_CHANGESET_NULLFREE(pCtx, pChangeset); SG_STRINGARRAY_NULLFREE(pCtx, pPaths); SG_RBTREE_ITERATOR_NULLFREE(pCtx, rb_it); return; }
void u0048_multidag__new_repo( SG_context * pCtx, const char* pszRidescName, SG_repo** ppResult ) { SG_vhash* pvhPartialDescriptor = NULL; SG_repo* pRepo = NULL; const SG_vhash* pvhActualDescriptor = NULL; SG_changeset* pcsFirst = NULL; char* pszidGidActualRoot = NULL; const char* pszidFirstChangeset = NULL; char buf_repo_id[SG_GID_BUFFER_LENGTH]; char buf_admin_id[SG_GID_BUFFER_LENGTH]; VERIFY_ERR_CHECK( SG_gid__generate(pCtx, buf_repo_id, sizeof(buf_repo_id)) ); VERIFY_ERR_CHECK( SG_gid__generate(pCtx, buf_admin_id, sizeof(buf_admin_id)) ); VERIFY_ERR_CHECK( SG_closet__get_partial_repo_instance_descriptor_for_new_local_repo(pCtx, &pvhPartialDescriptor) ); /* This test case writes dag nodes which are not real. They don't have a * changeset associated with them. So, if we use a caching repo, the * caching code will fail because it tries to load a changeset * which doesn't exist. So, we strip down to a raw repo here. */ VERIFY_ERR_CHECK( SG_repo__create_repo_instance(pCtx,pvhPartialDescriptor,SG_TRUE,NULL,buf_repo_id,buf_admin_id,&pRepo) ); VERIFY_ERR_CHECK( sg_zing__init_new_repo(pCtx, pRepo) ); VERIFY_ERR_CHECK( SG_repo__create_user_root_directory(pCtx, pRepo, "@", &pcsFirst, &pszidGidActualRoot) ); VERIFY_ERR_CHECK( SG_changeset__get_id_ref(pCtx, pcsFirst, &pszidFirstChangeset) ); VERIFY_ERR_CHECK( SG_repo__get_descriptor(pCtx, pRepo, &pvhActualDescriptor) ); /* TODO should this give an error if the ridesc name already exists? */ VERIFY_ERR_CHECK( SG_closet__descriptors__add(pCtx, pszRidescName, pvhActualDescriptor) ); SG_NULLFREE(pCtx, pszidGidActualRoot); SG_CHANGESET_NULLFREE(pCtx, pcsFirst); SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor); *ppResult = pRepo; return; fail: SG_VHASH_NULLFREE(pCtx, pvhPartialDescriptor); SG_REPO_NULLFREE(pCtx, pRepo); return; }
void SG_group__add_users( SG_context* pCtx, SG_repo* pRepo, const char* psz_group_name, const char** paszMemberNames, SG_uint32 count_names ) { char* psz_hid_cs_leaf = NULL; SG_zingtx* pztx = NULL; SG_dagnode* pdn = NULL; SG_changeset* pcs = NULL; SG_audit q; SG_uint32 i = 0; char* psz_recid_group = NULL; char* psz_recid_user = NULL; SG_ERR_CHECK( SG_zing__get_leaf__fail_if_needs_merge(pCtx, pRepo, SG_DAGNUM__USERS, &psz_hid_cs_leaf) ); SG_ERR_CHECK( SG_audit__init(pCtx, &q, pRepo, SG_AUDIT__WHEN__NOW, SG_AUDIT__WHO__FROM_SETTINGS) ); // lookup the recid of the group SG_ERR_CHECK( SG_zing__lookup_recid(pCtx, pRepo, SG_DAGNUM__USERS, psz_hid_cs_leaf, "group", "name", psz_group_name, &psz_recid_group) ); /* start a changeset */ SG_ERR_CHECK( SG_zing__begin_tx(pCtx, pRepo, SG_DAGNUM__USERS, q.who_szUserId, psz_hid_cs_leaf, &pztx) ); SG_ERR_CHECK( SG_zingtx__add_parent(pCtx, pztx, psz_hid_cs_leaf) ); for (i=0; i<count_names; i++) { // lookup the recid of the user SG_ERR_CHECK( SG_zing__lookup_recid(pCtx, pRepo, SG_DAGNUM__USERS, psz_hid_cs_leaf, "user", "email", paszMemberNames[i], &psz_recid_user) ); SG_ERR_CHECK( SG_zingtx__add_link__unpacked(pCtx, pztx, psz_recid_user, psz_recid_group, "member") ); SG_NULLFREE(pCtx, psz_recid_user); } /* commit the changes */ SG_ERR_CHECK( SG_zing__commit_tx(pCtx, q.when_int64, &pztx, &pcs, &pdn, NULL) ); // fall thru fail: if (pztx) { SG_ERR_IGNORE( SG_zing__abort_tx(pCtx, &pztx) ); } SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_NULLFREE(pCtx, psz_recid_group); SG_NULLFREE(pCtx, psz_recid_user); SG_DAGNODE_NULLFREE(pCtx, pdn); SG_CHANGESET_NULLFREE(pCtx, pcs); }
void SG_group__create( SG_context* pCtx, SG_repo* pRepo, const char* psz_name ) { char* psz_hid_cs_leaf = NULL; SG_zingtx* pztx = NULL; SG_zingrecord* prec = NULL; SG_dagnode* pdn = NULL; SG_changeset* pcs = NULL; SG_zingtemplate* pzt = NULL; SG_zingfieldattributes* pzfa = NULL; SG_audit q; SG_ERR_CHECK( SG_zing__get_leaf__fail_if_needs_merge(pCtx, pRepo, SG_DAGNUM__USERS, &psz_hid_cs_leaf) ); SG_ERR_CHECK( SG_audit__init(pCtx, &q, pRepo, SG_AUDIT__WHEN__NOW, SG_AUDIT__WHO__FROM_SETTINGS) ); /* start a changeset */ SG_ERR_CHECK( SG_zing__begin_tx(pCtx, pRepo, SG_DAGNUM__USERS, q.who_szUserId, psz_hid_cs_leaf, &pztx) ); SG_ERR_CHECK( SG_zingtx__add_parent(pCtx, pztx, psz_hid_cs_leaf) ); SG_ERR_CHECK( SG_zingtx__get_template(pCtx, pztx, &pzt) ); SG_ERR_CHECK( SG_zingtx__create_new_record(pCtx, pztx, "group", &prec) ); SG_ERR_CHECK( SG_zingtemplate__get_field_attributes(pCtx, pzt, "group", "name", &pzfa) ); SG_ERR_CHECK( SG_zingrecord__set_field__string(pCtx, prec, pzfa, psz_name) ); /* commit the changes */ SG_ERR_CHECK( SG_zing__commit_tx(pCtx, q.when_int64, &pztx, &pcs, &pdn, NULL) ); // fall thru fail: if (pztx) { SG_ERR_IGNORE( SG_zing__abort_tx(pCtx, &pztx) ); } SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_DAGNODE_NULLFREE(pCtx, pdn); SG_CHANGESET_NULLFREE(pCtx, pcs); }
/** * Create a new repo in the closet. */ static void _vv_verbs__init_new_repo__do_init(SG_context * pCtx, const char * pszRepoName, const char * pszStorage, const char * pszHashMethod, const char * psz_shared_users, SG_bool bFromUserMaster, char ** ppszGidRepoId, char ** ppszHidCSetFirst) { SG_repo * pRepo = NULL; SG_repo * pRepoUserMaster = NULL; char * pszUserMasterAdminId = NULL; SG_changeset * pCSetFirst = NULL; const char * pszHidCSetFirst_ref; char * pszHidCSetFirst = NULL; char * pszGidRepoId = NULL; char bufAdminId[SG_GID_BUFFER_LENGTH]; // create a completely new repo in the closet. SG_NULLARGCHECK_RETURN( pszRepoName ); // pszStorage is optional // pszHashMethod is optional SG_ASSERT(SG_FALSE == (psz_shared_users && bFromUserMaster)); // checked in SG_vv_verbs__init_new_repo if (psz_shared_users) { SG_ERR_CHECK( _vv_verbs__init_new_repo__get_admin_id(pCtx, psz_shared_users, bufAdminId) ); } else if (bFromUserMaster) { SG_ERR_CHECK( SG_REPO__USER_MASTER__OPEN(pCtx, &pRepoUserMaster) ); SG_ERR_CHECK( SG_repo__get_admin_id(pCtx, pRepoUserMaster, &pszUserMasterAdminId) ); memcpy(bufAdminId, pszUserMasterAdminId, sizeof(bufAdminId)); //SG_memcpy2(pszUserMasterAdminId, bufAdminId); SG_NULLFREE(pCtx, pszUserMasterAdminId); } else { SG_ERR_CHECK( SG_gid__generate(pCtx, bufAdminId, sizeof(bufAdminId)) ); } SG_ERR_CHECK( SG_repo__create__completely_new__empty__closet(pCtx, bufAdminId, pszStorage, pszHashMethod, pszRepoName) ); SG_ERR_CHECK( SG_REPO__OPEN_REPO_INSTANCE(pCtx, pszRepoName, &pRepo) ); if (!psz_shared_users && !bFromUserMaster) { SG_ERR_CHECK( SG_user__create_nobody(pCtx, pRepo) ); } SG_ERR_CHECK( SG_repo__setup_basic_stuff(pCtx, pRepo, &pCSetFirst, NULL) ); if (psz_shared_users) { SG_ERR_CHECK( SG_pull__admin(pCtx, pRepo, psz_shared_users, NULL, NULL, NULL, NULL) ); } else if (bFromUserMaster) { SG_ERR_CHECK( SG_pull__admin__local(pCtx, pRepo, pRepoUserMaster, NULL) ); } SG_ERR_CHECK( SG_changeset__get_id_ref(pCtx, pCSetFirst, &pszHidCSetFirst_ref) ); SG_ERR_CHECK( SG_STRDUP(pCtx, pszHidCSetFirst_ref, &pszHidCSetFirst) ); SG_ERR_CHECK( SG_repo__get_repo_id(pCtx, pRepo, &pszGidRepoId) ); *ppszGidRepoId = pszGidRepoId; *ppszHidCSetFirst = pszHidCSetFirst; SG_REPO_NULLFREE(pCtx, pRepo); SG_REPO_NULLFREE(pCtx, pRepoUserMaster); SG_CHANGESET_NULLFREE(pCtx, pCSetFirst); return; fail: /* If we fail to pull the admin dags after the repo's been created, delete it. */ if (pRepo) { SG_REPO_NULLFREE(pCtx, pRepo); if (pszRepoName) SG_ERR_IGNORE( _vv_verbs__init_new_repo__delete_new_repo(pCtx, pszRepoName) ); } SG_REPO_NULLFREE(pCtx, pRepoUserMaster); SG_CHANGESET_NULLFREE(pCtx, pCSetFirst); SG_NULLFREE(pCtx, pszGidRepoId); SG_NULLFREE(pCtx, pszHidCSetFirst); }
static void _do_since( SG_context* pCtx, SG_repo* pRepo, SG_vhash* pvh_since, SG_fragball_writer* pfb ) { SG_uint32 count_dagnums = 0; SG_uint32 i_dagnum = 0; SG_ihash* pih_new = NULL; SG_rbtree* prb = NULL; SG_vhash* pvh_blobs = NULL; SG_changeset* pcs = NULL; SG_NULLARGCHECK_RETURN(pRepo); SG_NULLARGCHECK_RETURN(pvh_since); SG_NULLARGCHECK_RETURN(pfb); // TODO do we need to deal with dags which are present here but not in pvh_since? SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_since, &count_dagnums) ); for (i_dagnum=0; i_dagnum<count_dagnums; i_dagnum++) { const char* psz_dagnum = NULL; SG_varray* pva_nodes = NULL; SG_uint64 dagnum = 0; SG_ERR_CHECK( SG_vhash__get_nth_pair__varray(pCtx, pvh_since, i_dagnum, &psz_dagnum, &pva_nodes) ); SG_ERR_CHECK( SG_dagnum__from_sz__hex(pCtx, psz_dagnum, &dagnum) ); SG_ERR_CHECK( SG_repo__find_new_dagnodes_since(pCtx, pRepo, dagnum, pva_nodes, &pih_new) ); if (pih_new) { SG_uint32 count = 0; SG_ERR_CHECK( SG_ihash__count(pCtx, pih_new, &count) ); if (count) { SG_uint32 i = 0; SG_ERR_CHECK( SG_rbtree__alloc(pCtx, &prb) ); SG_ERR_CHECK( SG_vhash__alloc(pCtx, &pvh_blobs) ); for (i=0; i<count; i++) { const char* psz_node = NULL; SG_ERR_CHECK( SG_ihash__get_nth_pair(pCtx, pih_new, i, &psz_node, NULL) ); SG_ERR_CHECK( SG_rbtree__add(pCtx, prb, psz_node) ); SG_ERR_CHECK( SG_vhash__add__null(pCtx, pvh_blobs, psz_node) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_node, &pcs) ); SG_ERR_CHECK( _add_necessary_blobs(pCtx, pcs, pvh_blobs) ); SG_CHANGESET_NULLFREE(pCtx, pcs); } // put all these new nodes in the frag SG_ERR_CHECK( SG_fragball__write__dagnodes(pCtx, pfb, dagnum, prb) ); // and the blobs SG_ERR_CHECK( SG_sync__add_blobs_to_fragball(pCtx, pfb, pvh_blobs) ); SG_VHASH_NULLFREE(pCtx, pvh_blobs); SG_RBTREE_NULLFREE(pCtx, prb); } SG_IHASH_NULLFREE(pCtx, pih_new); } } fail: SG_CHANGESET_NULLFREE(pCtx, pcs); SG_VHASH_NULLFREE(pCtx, pvh_blobs); SG_RBTREE_NULLFREE(pCtx, prb); SG_IHASH_NULLFREE(pCtx, pih_new); }
void SG_workingdir__create_and_get( SG_context* pCtx, const char* pszDescriptorName, const SG_pathname* pPathDirPutTopLevelDirInHere, SG_bool bCreateDrawer, const char* psz_spec_hid_cs_baseline ) { SG_repo* pRepo = NULL; SG_rbtree* pIdsetLeaves = NULL; SG_uint32 count_leaves = 0; SG_changeset* pcs = NULL; const char* pszidUserSuperRoot = NULL; SG_bool b = SG_FALSE; char* psz_hid_cs_baseline = NULL; SG_pendingtree * pPendingTree = NULL; SG_vhash * pvhTimestamps = NULL; /* * Fetch the descriptor by its given name and use it to connect to * the repo. */ SG_ERR_CHECK( SG_repo__open_repo_instance(pCtx, pszDescriptorName, &pRepo) ); if (psz_spec_hid_cs_baseline) { SG_ERR_CHECK( SG_strdup(pCtx, psz_spec_hid_cs_baseline, &psz_hid_cs_baseline) ); } else { const char* psz_hid = NULL; /* * If you do not specify a hid to be the baseline, then this routine * currently only works if there is exactly one leaf in the repo. */ SG_ERR_CHECK( SG_repo__fetch_dag_leaves(pCtx, pRepo,SG_DAGNUM__VERSION_CONTROL,&pIdsetLeaves) ); SG_ERR_CHECK( SG_rbtree__count(pCtx, pIdsetLeaves, &count_leaves) ); if (count_leaves != 1) SG_ERR_THROW( SG_ERR_MULTIPLE_HEADS_FROM_DAGNODE ); SG_ERR_CHECK( SG_rbtree__iterator__first(pCtx, NULL, pIdsetLeaves, &b, &psz_hid, NULL) ); SG_ERR_CHECK( SG_STRDUP(pCtx, psz_hid, &psz_hid_cs_baseline) ); } /* * Load the desired changeset from the repo so we can look up the * id of its user root directory */ SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_hid_cs_baseline, &pcs) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pcs, &pszidUserSuperRoot) ); if (bCreateDrawer) { SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvhTimestamps) ); // Retrieve everything into the WD and capture the timestamps on the files that we create. SG_ERR_CHECK( sg_workingdir__do_get_dir__top(pCtx, pRepo, pPathDirPutTopLevelDirInHere, pszidUserSuperRoot, pvhTimestamps) ); // this creates "repo.json" with the repo-descriptor. SG_ERR_CHECK( SG_workingdir__set_mapping(pCtx, pPathDirPutTopLevelDirInHere, pszDescriptorName, NULL) ); // this creates an empty "wd.json" file (which doesn't know anything). SG_ERR_CHECK( SG_PENDINGTREE__ALLOC(pCtx, pPathDirPutTopLevelDirInHere, SG_TRUE, &pPendingTree) ); // force set the initial parents to the current changeset. SG_ERR_CHECK( SG_pendingtree__set_single_wd_parent(pCtx, pPendingTree, psz_hid_cs_baseline) ); // force initialize the timestamp cache to the list that we just built; this should // be the only timestamps in the cache since we just populated the WD. SG_ERR_CHECK( SG_pendingtree__set_wd_timestamp_cache(pCtx, pPendingTree, &pvhTimestamps) ); // this steals our vhash SG_ERR_CHECK( SG_pendingtree__save(pCtx, pPendingTree) ); } else { // Retrieve everything into the WD but do not create .sgdrawer or record timestamps. // This is more like an EXPORT operation. SG_ERR_CHECK( sg_workingdir__do_get_dir__top(pCtx, pRepo, pPathDirPutTopLevelDirInHere, pszidUserSuperRoot, NULL) ); } fail: SG_VHASH_NULLFREE(pCtx, pvhTimestamps); SG_NULLFREE(pCtx, psz_hid_cs_baseline); SG_CHANGESET_NULLFREE(pCtx, pcs); SG_RBTREE_NULLFREE(pCtx, pIdsetLeaves); SG_REPO_NULLFREE(pCtx, pRepo); SG_PENDINGTREE_NULLFREE(pCtx, pPendingTree); }
static void loop_innards_make_delta( SG_context* pCtx, SG_repo* pRepo, SG_varray* pva_path, SG_uint32 i_path_step, SG_vhash* pvh_add, SG_vhash* pvh_remove ) { SG_changeset* pcs = NULL; const char* psz_csid_cur = NULL; const char* psz_csid_parent = NULL; SG_vhash* pvh_changes = NULL; SG_vhash* pvh_one_parent_changes = NULL; SG_vhash* pvh_cs_add = NULL; SG_vhash* pvh_cs_remove = NULL; SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_path, i_path_step, &psz_csid_cur) ); SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_path, i_path_step + 1, &psz_csid_parent) ); SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_csid_cur, &pcs) ); SG_ERR_CHECK( SG_changeset__db__get_changes(pCtx, pcs, &pvh_changes) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_changes, psz_csid_parent, &pvh_one_parent_changes) ); SG_ERR_CHECK( SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "add", &pvh_cs_remove) ); SG_ERR_CHECK( SG_vhash__check__vhash(pCtx, pvh_one_parent_changes, "remove", &pvh_cs_add) ); if (pvh_cs_add) { SG_uint32 count = 0; SG_uint32 i = 0; SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_cs_add, &count) ); for (i=0; i<count; i++) { const char* psz_hid_rec = NULL; SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_cs_add, i, &psz_hid_rec, NULL) ); SG_ERR_CHECK( SG_vhash__remove_if_present(pCtx, pvh_remove, psz_hid_rec, &b) ); if (!b) { SG_ERR_CHECK( SG_vhash__update__null(pCtx, pvh_add, psz_hid_rec) ); } } } if (pvh_cs_remove) { SG_uint32 count = 0; SG_uint32 i = 0; SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_cs_remove, &count) ); for (i=0; i<count; i++) { const char* psz_hid_rec = NULL; SG_bool b = SG_FALSE; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_cs_remove, i, &psz_hid_rec, NULL) ); SG_ERR_CHECK( SG_vhash__remove_if_present(pCtx, pvh_add, psz_hid_rec, &b) ); if (!b) { SG_ERR_CHECK( SG_vhash__update__null(pCtx, pvh_remove, psz_hid_rec) ); } } } fail: SG_CHANGESET_NULLFREE(pCtx, pcs); }
void SG_vc_hooks__install( SG_context* pCtx, SG_repo* pRepo, const char* psz_interface, const char* psz_js, const char *module, SG_uint32 version, SG_bool replaceOld, const SG_audit* pq ) { char* psz_hid_cs_leaf = NULL; SG_zingtx* pztx = NULL; SG_zingrecord* prec = NULL; SG_dagnode* pdn = NULL; SG_changeset* pcs = NULL; SG_zingtemplate* pzt = NULL; SG_zingfieldattributes* pzfa = NULL; SG_varray *oldRecs = NULL; SG_UNUSED(module); SG_UNUSED(version); if (replaceOld) { SG_ERR_CHECK( SG_vc_hooks__lookup_by_interface(pCtx, pRepo, psz_interface, &oldRecs) ); } // TODO consider validating the JS by compiling it SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepo, NULL, SG_DAGNUM__VC_HOOKS, &psz_hid_cs_leaf) ); /* start a changeset */ SG_ERR_CHECK( SG_zing__begin_tx(pCtx, pRepo, SG_DAGNUM__VC_HOOKS, pq->who_szUserId, psz_hid_cs_leaf, &pztx) ); SG_ERR_CHECK( SG_zingtx__add_parent(pCtx, pztx, psz_hid_cs_leaf) ); if (replaceOld) { SG_uint32 i, count; SG_ERR_CHECK( SG_varray__count(pCtx, oldRecs, &count) ); for ( i = 0; i < count; ++i ) { const char *hidrec = NULL; SG_vhash *rec = NULL; SG_ERR_CHECK( SG_varray__get__vhash(pCtx, oldRecs, i, &rec) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, rec, "hidrec", &hidrec) ); SG_ERR_CHECK( SG_zingtx__delete_record__hid(pCtx, pztx, "hook", hidrec) ); } } SG_ERR_CHECK( SG_zingtx__get_template(pCtx, pztx, &pzt) ); SG_ERR_CHECK( SG_zingtx__create_new_record(pCtx, pztx, "hook", &prec) ); SG_ERR_CHECK( SG_zingtemplate__get_field_attributes(pCtx, pzt, "hook", "interface", &pzfa) ); SG_ERR_CHECK( SG_zingrecord__set_field__string(pCtx, prec, pzfa, psz_interface) ); SG_ERR_CHECK( SG_zingtemplate__get_field_attributes(pCtx, pzt, "hook", "js", &pzfa) ); SG_ERR_CHECK( SG_zingrecord__set_field__string(pCtx, prec, pzfa, psz_js) ); if (module) { SG_ERR_CHECK( SG_zingtemplate__get_field_attributes(pCtx, pzt, "hook", "module", &pzfa) ); SG_ERR_CHECK( SG_zingrecord__set_field__string(pCtx, prec, pzfa, module) ); } if (version) { SG_ERR_CHECK( SG_zingtemplate__get_field_attributes(pCtx, pzt, "hook", "version", &pzfa) ); SG_ERR_CHECK( SG_zingrecord__set_field__int(pCtx, prec, pzfa, (SG_int64)version) ); } /* commit the changes */ SG_ERR_CHECK( SG_zing__commit_tx(pCtx, pq->when_int64, &pztx, &pcs, &pdn, NULL) ); // fall thru fail: if (pztx) { SG_ERR_IGNORE( SG_zing__abort_tx(pCtx, &pztx) ); } SG_VARRAY_NULLFREE(pCtx, oldRecs); SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_DAGNODE_NULLFREE(pCtx, pdn); SG_CHANGESET_NULLFREE(pCtx, pcs); }
void sg_vc_hooks__lookup_by_interface__single_result( SG_context* pCtx, SG_repo* pRepo, const char* psz_interface, SG_vhash** ppvh_latest_version ) { //This version will return only the hook with the largest version. //If multiple versions of the hook are defined, //all old versions will be deleted. SG_varray* pva_hooks = NULL; SG_vhash* pvh_latest_hook = NULL; SG_zingtx* pztx = NULL; char* psz_hid_cs_leaf = NULL; SG_dagnode* pdn = NULL; SG_changeset* pcs = NULL; SG_ERR_CHECK( SG_vc_hooks__lookup_by_interface( pCtx, pRepo, psz_interface, &pva_hooks ) ); if (!pva_hooks) { SG_ERR_THROW2( SG_ERR_VC_HOOK_MISSING, (pCtx, "%s", psz_interface) ); } else { SG_uint32 count = 0; SG_ERR_CHECK( SG_varray__count(pCtx, pva_hooks, &count) ); if (0 == count) { SG_ERR_THROW2( SG_ERR_VC_HOOK_MISSING, (pCtx, "%s", psz_interface) ); } else { if (count > 1) { SG_uint32 i = 0; SG_int32 nVersion = 0; SG_int32 nHighestVersion = -1; SG_int32 nAmbiguousVersion = -2; const char * hidRecToSave = NULL; const char * hidrec = NULL; SG_vhash * pvh_current_hook = NULL; //There are multiple versions installed for this hook. //delete the lesser numbered versions. for (i=0; i < count; i++) { SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pva_hooks, i, &pvh_current_hook) ); SG_ERR_CHECK( SG_vhash__get__int32(pCtx, pvh_current_hook, "version", &nVersion) ); if (nVersion == nHighestVersion) { nAmbiguousVersion = nHighestVersion; } if (nVersion > nHighestVersion) { nHighestVersion = nVersion; SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_current_hook, "hidrec", &hidRecToSave) ); } } if (nAmbiguousVersion == nHighestVersion) SG_ERR_THROW2( SG_ERR_VC_HOOK_AMBIGUOUS, (pCtx, "%s defined multiple times at version %d", psz_interface, nHighestVersion) ); if (nHighestVersion > 0 && hidRecToSave != NULL) { SG_audit q; SG_ERR_CHECK( SG_audit__init(pCtx,&q,pRepo,SG_AUDIT__WHEN__NOW,SG_AUDIT__WHO__FROM_SETTINGS) ); SG_ERR_CHECK( SG_zing__get_leaf(pCtx, pRepo, NULL, SG_DAGNUM__VC_HOOKS, &psz_hid_cs_leaf) ); /* start a changeset */ SG_ERR_CHECK( SG_zing__begin_tx(pCtx, pRepo, SG_DAGNUM__VC_HOOKS, q.who_szUserId, psz_hid_cs_leaf, &pztx) ); SG_ERR_CHECK( SG_zingtx__add_parent(pCtx, pztx, psz_hid_cs_leaf) ); for (i=0; i < count; i++) { SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pva_hooks, i, &pvh_current_hook) ); SG_ERR_CHECK( SG_vhash__get__sz(pCtx, pvh_current_hook, "hidrec", &hidrec) ); if (SG_strcmp__null(hidrec, hidRecToSave) != 0) { //This isn't the recid to save. Delete it! SG_ERR_CHECK( SG_zingtx__delete_record__hid(pCtx, pztx, "hook", hidrec) ); } } /* commit the changes */ SG_ERR_CHECK( SG_zing__commit_tx(pCtx, q.when_int64, &pztx, &pcs, &pdn, NULL) ); } } else { //There's only one hook installed return it. SG_vhash * pvh_temp = NULL; SG_ERR_CHECK( SG_varray__get__vhash(pCtx, pva_hooks, 0, &pvh_temp) ); SG_ERR_CHECK( SG_VHASH__ALLOC__COPY(pCtx, &pvh_latest_hook, pvh_temp) ); } } } SG_RETURN_AND_NULL(pvh_latest_hook, ppvh_latest_version); fail: if (pztx) { SG_ERR_IGNORE( SG_zing__abort_tx(pCtx, &pztx) ); } SG_NULLFREE(pCtx, psz_hid_cs_leaf); SG_DAGNODE_NULLFREE(pCtx, pdn); SG_CHANGESET_NULLFREE(pCtx, pcs); SG_VARRAY_NULLFREE(pCtx, pva_hooks); }
void sg_pack__do_changeset(SG_context* pCtx, SG_repo* pRepo, const char* psz_hid_cs, SG_rbtree* prb_blobs) { SG_changeset* pcs = NULL; SG_int32 gen = 0; SG_uint32 count_blobs = 0; SG_uint32 count_parents = 0; SG_varray* pva_parents = NULL; SG_uint32 i; SG_rbtree* prb_new = NULL; const char* psz_hid_root_treenode = NULL; const char* psz_key = NULL; SG_vhash* pvh_lbl = NULL; SG_vhash* pvh_blobs = NULL; SG_ERR_CHECK( SG_changeset__load_from_repo(pCtx, pRepo, psz_hid_cs, &pcs) ); SG_ERR_CHECK( SG_changeset__get_root(pCtx, pcs, &psz_hid_root_treenode) ); SG_ERR_CHECK( SG_changeset__get_generation(pCtx, pcs, &gen) ); SG_ERR_CHECK( SG_RBTREE__ALLOC__PARAMS(pCtx, &prb_new, count_blobs, NULL) ); SG_ERR_CHECK( SG_changeset__get_list_of_bloblists(pCtx, pcs, &pvh_lbl) ); /* add all the tree user file blobs */ SG_ERR_CHECK( SG_changeset__get_bloblist_name(pCtx, SG_BLOB_REFTYPE__TREEUSERFILE, &psz_key) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_lbl, psz_key, &pvh_blobs) ); SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_blobs, &count_blobs) ); /* now write all the blobs */ for (i=0; i<count_blobs; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_vhash__get_nth_pair(pCtx, pvh_blobs, i, &psz_hid, NULL) ); SG_ERR_CHECK( SG_rbtree__add(pCtx, prb_new, psz_hid) ); } /* and the treenode blobs */ SG_ERR_CHECK( SG_changeset__get_bloblist_name(pCtx, SG_BLOB_REFTYPE__TREENODE, &psz_key) ); SG_ERR_CHECK( SG_vhash__get__vhash(pCtx, pvh_lbl, psz_key, &pvh_blobs) ); SG_ERR_CHECK( SG_vhash__count(pCtx, pvh_blobs, &count_blobs) ); /* now write all the blobs */ for (i=0; i<count_blobs; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_rbtree__add(pCtx, prb_new, psz_hid) ); } SG_ERR_CHECK( sg_pack__do_get_dir__top(pCtx, pRepo, gen, psz_hid_root_treenode, prb_blobs, prb_new) ); SG_RBTREE_NULLFREE(pCtx, prb_new); SG_ERR_CHECK( SG_changeset__get_parents(pCtx, pcs, &pva_parents) ); if (pva_parents) { SG_ERR_CHECK( SG_varray__count(pCtx, pva_parents, &count_parents) ); for (i=0; i<count_parents; i++) { const char* psz_hid = NULL; SG_ERR_CHECK( SG_varray__get__sz(pCtx, pva_parents, i, &psz_hid) ); SG_ERR_CHECK( sg_pack__do_changeset(pCtx, pRepo, psz_hid, prb_blobs) ); } } SG_CHANGESET_NULLFREE(pCtx, pcs); return; fail: SG_RBTREE_NULLFREE(pCtx, prb_new); }