/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* Copyright 2013-2021 Stephan Beal (https://wanderinghorse.net). Derived heavily from previous work: Copyright (c) 2013 D. Richard Hipp (https://www.hwaci.com/drh/) This program is free software; you can redistribute it and/or modify it under the terms of the Simplified BSD License (also known as the "2-Clause License" or "FreeBSD License".) This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. ***************************************************************************** This file implements the code to checkout a Fossil repository. */ #include "fossil-scm/fossil-cli.h" /* Fossil App mini-framework */ #include "fossil-scm/fossil-core.h" #include "fossil-scm/fossil-db.h" #include "fossil-scm/fossil-internal.h" #include "fossil-scm/fossil-util.h" #include #include #define MARKER(pfexp) \ do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); \ printf pfexp; \ } while(0) static int verbose = 0; typedef struct { int extracted; int kept; bool quiet; } extract_state; static int fsl_repo_checkout_f_my(fsl_repo_checkout_state const *coState) { enum {DATE_SHORT = 16}; fsl_repo_extract_state const * xs = coState->xState; extract_state *state = (extract_state *)coState->callbackState; static char tbuf[DATE_SHORT]; char mode = '?'; if(coState->fileWasWritten) { mode = '+'; ++state->extracted; }else{ mode = '!'; ++state->kept; } if(!state->quiet){ fsl_strftime_unix(tbuf, DATE_SHORT, "%d %b %Y", coState->mtime, 1); f_out("[%c] %8"FSL_SIZE_T_PFMT" %s %s\n", mode, coState->size, tbuf, xs->fc->name); } return 0; } int main(int argc, char const * const *argv) { fsl_db *db = 0; extract_state ex = {0,0,0}; fsl_cx *f = NULL; fsl_id_t prevId = 0, rid = 0; const char *sym = NULL; bool force = false, keep = false, manifest = false, mtime = false, q = false, doRm = true; int rc = 0; fcli_cliflag fcli_flags[] = { FCLI_FLAG_BOOL("f", "force", &force, "Continue with the checkout " "irrespective of any unsaved changes in the current checkout."), FCLI_FLAG_BOOL(0, "keep", &keep, "Only checkout files from the requested " " that do not have a file of the same name already present on " "disk. Files with the same name as those from the requested will" " remain unmodified irrespective of whether their content is consistent " "with that of the requested . In such a case, the checkout will " "immediately be in a changed state, which 'f-status' will report."), FCLI_FLAG_BOOL(0, "manifest", &manifest, "Only modify the manifest and manifest.uuid files."), FCLI_FLAG_BOOL("q", "quiet", &q, "Suppress non-error output unless --verbose is used."), FCLI_FLAG_BOOL(0, "setmtime", &mtime, "Set timestamps of all files to that " "of the last check-in in which they were modified (i.e., manifest time)."), FCLI_FLAG_BOOL_INVERT(0,"no-rm", &doRm, "Do not delete files which were removed between the " "original and new checkout versions."), fcli_cliflag_empty_m }; fcli_help_info fcli_help = { "Change the current checkout to the requested or to the tip of " "the trunk if no is specified.\n", "[]\n", NULL }; fcli.cliFlags = fcli_flags; fcli.appHelp = &fcli_help; rc = fcli_setup(argc, argv); if (rc == FCLI_RC_HELP) return 0; else if (rc) goto end; f = fcli.f; db = fsl_needs_checkout(f); if(!db){ goto end; } verbose = fcli_is_verbose(); if(!verbose){ verbose = !q; } if(fcli_has_unused_flags(0)){ goto end; } rc = fsl_cx_transaction_begin(f); if(rc) goto end; fsl_checkout_version_info(f, &prevId, NULL); fsl_checkout_changes_scan(f); if(!force && fsl_checkout_has_changes(f)) { fcli_err_set(FSL_RC_ALREADY_EXISTS, "The current checkout contains unsaved changes."); goto end; } if(force){ fsl_checkout_clear_db(f); } if(!(sym = fcli_next_arg(1))){ char * mainBranch = fsl_config_get_text(f, FSL_CONFDB_REPO, "main-branch", 0); if(mainBranch){ fcli_fax(mainBranch); sym = mainBranch; }else{ sym = "trunk"; } } rc = fsl_sym_to_rid(f, sym, FSL_SATYPE_CHECKIN, &rid); if(rc) goto end; if(prevId == rid){ f_out("Same version - nothing to do.\n"); goto end; } ex.extracted = 0; ex.kept = 0; ex.quiet = q; fsl_repo_checkout_opt cOpt = fsl_repo_checkout_opt_empty; cOpt.dryRun = fcli.fDryRun; cOpt.vid = rid; cOpt.callback = fsl_repo_checkout_f_my; cOpt.callbackState = &ex; cOpt.fileOverwritePolicy = keep ? FSL_OVERWRITE_NEVER : FSL_OVERWRITE_ALWAYS; cOpt.rmMissingFiles = doRm; rc = fsl_repo_checkout(f, &cOpt); if(rc) goto end; f_out("\nChecked out %d file(s) from %s [RID: %"FSL_ID_T_PFMT"].\n", ex.extracted, sym, rid); if(ex.kept){ f_out("%d file(s) left unchanged on disk\n", ex.kept); } if(cOpt.dryRun){ f_out("Dry-run mode. Rolling back transaction.\n"); rc = fsl_cx_transaction_end(f, true); } end: if(fsl_cx_transaction_level(f)){ int const rc2 = fsl_cx_transaction_end(f, !!rc); rc = rc ? rc : fsl_cx_uplift_db_error2(f, db, rc2); } return fcli_end_of_main(rc); }