1#!/usr/local/bin/python3.8 2import os 3import sys 4import logging 5 6import re 7 8# THIS PART MUST BE EXACTLY IDENTICAL IN cado-nfs.py and cado-nfs-client.py 9 10# Three possible locations for this script 11# 12# The installed path. Then we should rely on the @-escaped paths, and 13# determine the location of all our utility stuff based on that. 14# 15# The build directory. We rely on the presence of a magic file called 16# source-location.txt, and we fetch the python source code from there 17# 18# The source tree. We call the ./scripts/build_environment.sh script to 19# determine where the binaries are being put. 20 21import subprocess 22import locale 23 24pathdict=dict() 25 26one_pyfile_example_subpath = "scripts/cadofactor/workunit.py" 27 28def detect_installed_tree(pathdict): 29 mydir = os.path.normpath(os.path.dirname(sys.argv[0])) 30 md = mydir.split(os.path.sep) 31 install_tree = mydir 32 bd = "@BINSUFFIX@".split(os.path.sep) 33 while md and bd and md[-1] == bd[-1]: 34 md.pop() 35 bd.pop() 36 install_tree = os.path.normpath(os.path.join(install_tree, "..")) 37 if bd: 38 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 39 print("{} does not end in @BINSUFFIX@".format(mydir)) 40 return False 41 example = os.path.join(install_tree, "@LIBSUFFIX@", one_pyfile_example_subpath) 42 t = os.path.exists(example) 43 if not t: 44 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 45 print("{} does not exist".format(example)) 46 return False 47 48 # make all this relocatable, it doesn't cost us much. 49 # (note though that the rpaths in the binaries are likely to still 50 # contain absolute paths) 51 pathdict["pylib"] = os.path.join(install_tree, "@LIBSUFFIX@/scripts/cadofactor") 52 pathdict["data"] = os.path.join(install_tree, "@DATASUFFIX@") 53 pathdict["lib"] = os.path.join(install_tree, "@LIBSUFFIX@") 54 pathdict["bin"] = os.path.join(install_tree, "@BINSUFFIX@") 55 56 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 57 print("cado-nfs running in installed tree") 58 return True 59 60def detect_build_tree(pathdict): 61 # source-location.txt is created by our build system, and can be used 62 # *ONLY* when we call this script from the build directory. We don't 63 # want this to perspire in any installed file, of course. 64 mydir = os.path.normpath(os.path.dirname(sys.argv[0])) 65 source_location_subpath = "source-location.txt" 66 source_location_file = os.path.join(mydir, source_location_subpath) 67 if not os.path.exists(source_location_file): 68 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 69 print("{} does not exist".format(source_location_file)) 70 return False 71 72 # ok, we're in the build tree, apparently 73 source_tree = open(source_location_file, "r").read().strip() 74 75 pathdict["pylib"] = os.path.join(source_tree, "scripts/cadofactor") 76 pathdict["data"] = os.path.join(source_tree, "parameters") 77 pathdict["lib"] = mydir 78 pathdict["bin"] = mydir 79 80 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 81 print("cado-nfs running in build tree") 82 return True 83 84def detect_source_tree(pathdict): 85 mydir = os.path.normpath(os.path.dirname(sys.argv[0])) 86 t = os.path.exists(os.path.join(mydir, one_pyfile_example_subpath)) 87 helper = os.path.join(mydir, "scripts/build_environment.sh") 88 if not os.path.exists(helper): 89 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 90 print("{} does not exist".format(helper)) 91 return False 92 pipe = subprocess.Popen([helper, "--show"], stdout=subprocess.PIPE) 93 loc = locale.getdefaultlocale()[1] 94 if not loc: 95 loc="ascii" 96 output = pipe.communicate()[0].decode(loc) 97 cado_bin_path = [x.split("=",2)[1] for x in output.split("\n") if re.match("^build_tree",x)][0] 98 cado_bin_path = re.sub("^\"(.*)\"$", "\\1", cado_bin_path) 99 100 pathdict["pylib"] = os.path.join(mydir, "scripts/cadofactor") 101 pathdict["data"] = os.path.join(mydir, "parameters") 102 pathdict["lib"] = cado_bin_path 103 pathdict["bin"] = cado_bin_path 104 105 if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"): 106 print("cado-nfs running in source tree") 107 return True 108 109if detect_installed_tree(pathdict): 110 pass 111elif detect_build_tree(pathdict): 112 pass 113elif detect_source_tree(pathdict): 114 pass 115else: 116 raise RuntimeError("We're unable to determine the location of the cado-nfs binaries and python files") 117 118sys.path.append(pathdict["pylib"]) 119 120# END OF THE PART THAT MUST BE EXACTLY IDENTICAL IN cado-nfs.py and cado-nfs-client.py 121 122 123import cadotask 124import cadologger 125import toplevel 126import itertools 127import wudb 128from cadocommand import shellquote 129 130if __name__ == '__main__': 131 # Parse command line arguments 132 133 # Some command-line arguments are really parsed only here, while some 134 # others are relevant to the whole hierarchy of cado-nfs programs. 135 # The (hairy) logic which is used to form the definitive list of 136 # parameters (in the cadoparams sense) from what we got here on the 137 # command line is grouped in the Cado_NFS_toplevel class, down in 138 # scripts/cadofactor/toplevel.py 139 140 toplevel_params = toplevel.Cado_NFS_toplevel() 141 for key, value in pathdict.items(): 142 toplevel_params.setpath(key, value) 143 logger = toplevel_params.logger 144 parameters, db = toplevel_params.get_cooked_parameters() 145 146 # We have to remove the credential info from the database which gets 147 # stored in the parameter snapshot. We must also make sure that we 148 # store this info always at the root of the param tree, or we may end 149 # up do bizarre things with duplicated keys if we resume from a 150 # parameter snapshot file *and* we have something on the command 151 # line. 152 if parameters.get_or_set_default("database", None): 153 parameters.replace("database", db.uri_without_credentials) 154 # do this so that the parameter does not appear unused. 155 parameters.get_or_set_default("database") 156 157 158 # well, this *must* exist, right ? 159 name = parameters.get_or_set_default("tasks.name") 160 wdir = parameters.get_or_set_default("tasks.workdir") 161 162 # Add a logger to capture the command lines of programs we run 163 cmdfilename = os.path.join(wdir, name + ".cmd") 164 logger.addHandler(cadologger.CmdFileHandler(cmdfilename)) 165 166 # Add a logger to write debugging information to a log file 167 filelvl = getattr(cadologger, toplevel_params.args.filelog.upper()) 168 logfilename = os.path.join(wdir, name + ".log") 169 filehandler = cadologger.FileHandler(filename = logfilename, lvl = filelvl) 170 logger.addHandler(filehandler) 171 172 173 cmdline=" ".join([shellquote(arg, idx == 0) for idx, arg in enumerate(sys.argv)]) 174 cmdline=cmdline.replace(db.uri, db.uri_without_credentials) 175 logger.info("Command line parameters: %s", cmdline) 176 177 178 logger.debug("Root parameter dictionary:\n%s", parameters) 179 180 181 # Write a snapshot of the parameters to a file 182 for counter in itertools.count(): 183 snapshot_basename = name + ".parameters_snapshot.%d" % counter 184 snapshot_filename = os.path.join(wdir, snapshot_basename) 185 if not os.path.isfile(snapshot_filename): 186 break 187 with open(snapshot_filename, "w") as snapshot_file: 188 logger.debug("Writing parameter snapshot to %s", snapshot_filename) 189 snapshot_file.write(str(parameters)) 190 snapshot_file.write("\n") 191 192 logger.info("If this computation gets interrupted, it can be resumed with %s %s", sys.argv[0], snapshot_filename) 193 194 factorjob = cadotask.CompleteFactorization(db=db, 195 parameters = parameters, 196 path_prefix = []) 197 198 if toplevel_params.args.verboseparam: 199 logger.info("Summary of all recognized parameters\n" + 200 factorjob.parameter_help) 201 202 factors = factorjob.run() 203 204 dlp_param = parameters.myparams({"dlp": False,}, "") 205 dlp = dlp_param["dlp"] 206 checkdlp_param = parameters.myparams({"checkdlp": True ,}, "") 207 checkdlp = checkdlp_param["checkdlp"] 208 target_param = parameters.myparams({"target": "",}, "") 209 target = target_param["target"] 210 if factors is None: 211 toplevel_params.purge_temp_files(nopurge=True) 212 sys.exit("Error occurred, terminating") 213 else: 214 toplevel_params.purge_temp_files() 215 216 if not dlp: 217 print(" ".join(factors)) 218 else: 219 if checkdlp: 220 p = int(factors[0]) 221 ell = int(factors[1]) 222 log2 = int(factors[2]) 223 log3 = int(factors[3]) 224 logger.info("Checking that log(2) and log(3) are consistent...") 225 logger.info(" p = " + str(p)) 226 logger.info(" ell = " + str(ell)) 227 logger.info(" log2 = " + str(log2)) 228 logger.info(" log3 = " + str(log3)) 229 assert (p-1) % ell == 0 230 assert pow(3, log2*((p-1) // ell), p) == pow(2, log3*((p-1) // ell), p) 231 if target != "": 232 logtarget = int(factors[4]) 233 logger.info("Also check log(target) vs log(2) ...") 234 assert pow(int(target), log2*((p-1) // ell), p) == pow(2, logtarget*((p-1) // ell), p) 235 else: 236 logger.info("No check was performed. Logarithms of the factor base elements are in %s" % factorjob.request_map[cadotask.Request.GET_DLOG_FILENAME]()) 237 if target != "": 238 logtarget = int(factors[4]) 239 logger.info("target = " + str(target)) 240 logger.info("log(target) = " + str(logtarget)) 241 print(str(logtarget)) 242 logger.info("If you want to compute a new target, run %s %s target=<target>", sys.argv[0], snapshot_filename) 243 244