duplicate.py (11838B)
1 #!/usr/bin/python3 2 3 # Python shell script for Duplicating IPlug Projects 4 # Oli Larkin 2012-2019 5 # License: WTFPL http://sam.zoy.org/wtfpl/COPYING 6 # Modified from this script by Bibha Tripathi http://code.activestate.com/recipes/435904-sedawk-python-script-to-rename-subdirectories-of-a/ 7 # Author accepts no responsibilty for wiping your hd 8 9 # NOTES: 10 # should work with Python2 or Python3 11 # not designed to be fool proof- think carefully about what you choose for a project name 12 # best to stick to standard characters in your project names - avoid spaces, numbers and dots 13 # windows users need to install python and set it up so you can run it from the command line 14 # see http://www.voidspace.org.uk/python/articles/command_line.shtml 15 # this involves adding the python folder e.g. C:\Python27\ to your %PATH% environment variable 16 17 # USAGE: 18 # duplicate.py [inputprojectname] [outputprojectname] [manufacturername] (outputpath) 19 20 # TODO: 21 # - indentation of directory structure 22 # - variable manufacturer name 23 24 25 from __future__ import generators 26 27 import fileinput, glob, string, sys, os, re, uuid, pprint, random 28 from shutil import copy, copytree, ignore_patterns, rmtree 29 from os.path import join 30 31 scriptpath = os.path.dirname(os.path.realpath(__file__)) 32 33 sys.path.insert(0, scriptpath + "/iPlug2/Scripts/") 34 35 from parse_config import parse_config, parse_xcconfig, set_uniqueid 36 37 VERSION = "0.95" 38 39 # binary files that we don't want to do find and replace inside 40 FILTERED_FILE_EXTENSIONS = [ 41 ".ico", 42 ".icns", 43 ".pdf", 44 ".png", 45 ".zip", 46 ".exe", 47 ".wav", 48 ".aif", 49 ".data", 50 ".wasm", 51 "mkcert", 52 ] 53 FILTERED_FILE_NAMES = [".DS_Store"] 54 # files that we don't want to duplicate 55 DONT_COPY = ( 56 ".vs", 57 "*.exe", 58 "*.dmg", 59 "*.pkg", 60 "*.mpkg", 61 "*.svn", 62 "*.ncb", 63 "*.suo", 64 "*sdf", 65 "ipch", 66 "*.layout", 67 "*.depend", 68 ".DS_Store", 69 "xcuserdata", 70 "*.aps", 71 ) 72 73 SUBFOLDERS_TO_SEARCH = [ 74 "projects", 75 "config", 76 "resources", 77 "installer", 78 "scripts", 79 "manual", 80 "xcschemes", 81 "xcshareddata", 82 "xcuserdata", 83 "en-osx.lproj", 84 "project.xcworkspace", 85 "Images.xcassets", 86 "build-web", 87 ] 88 89 90 def randomFourChar(chars=string.ascii_letters + string.digits): 91 return "".join(random.choice(chars) for _ in range(4)) 92 93 94 def checkdirname(name, searchproject): 95 "check if directory name matches with the given pattern" 96 print("") 97 if name == searchproject: 98 return True 99 else: 100 return False 101 102 103 def replacestrs(filename, s, r): 104 files = glob.glob(filename) 105 106 for line in fileinput.input(files, inplace=1): 107 line.find(s) 108 line = line.replace(s, r) 109 sys.stdout.write(line) 110 111 112 def replacestrsChop(filename, s, r): 113 files = glob.glob(filename) 114 115 for line in fileinput.input(files, inplace=1): 116 if line.startswith(s): 117 line = r + "\n" 118 sys.stdout.write(line) 119 120 121 def dirwalk( 122 dir, searchproject, replaceproject, searchman, replaceman, oldroot="", newroot="" 123 ): 124 for f in os.listdir(dir): 125 fullpath = os.path.join(dir, f) 126 127 if os.path.isdir(fullpath) and not os.path.islink(fullpath): 128 if checkdirname(f, searchproject + "-macOS.xcodeproj"): 129 os.rename( 130 fullpath, os.path.join(dir, replaceproject + "-macOS.xcodeproj") 131 ) 132 fullpath = os.path.join(dir, replaceproject + "-macOS.xcodeproj") 133 134 print("recursing in macOS xcode project directory: ") 135 for x in dirwalk( 136 fullpath, 137 searchproject, 138 replaceproject, 139 searchman, 140 replaceman, 141 oldroot, 142 newroot, 143 ): 144 yield x 145 elif checkdirname(f, searchproject + "-iOS.xcodeproj"): 146 os.rename( 147 fullpath, os.path.join(dir, replaceproject + "-iOS.xcodeproj") 148 ) 149 fullpath = os.path.join(dir, replaceproject + "-iOS.xcodeproj") 150 151 print("recursing in iOS xcode project directory: ") 152 for x in dirwalk( 153 fullpath, 154 searchproject, 155 replaceproject, 156 searchman, 157 replaceman, 158 oldroot, 159 newroot, 160 ): 161 yield x 162 elif checkdirname(f, searchproject + ".xcworkspace"): 163 os.rename(fullpath, os.path.join(dir, replaceproject + ".xcworkspace")) 164 fullpath = os.path.join(dir, replaceproject + ".xcworkspace") 165 166 print("recursing in main xcode workspace directory: ") 167 for x in dirwalk( 168 fullpath, 169 searchproject, 170 replaceproject, 171 searchman, 172 replaceman, 173 oldroot, 174 newroot, 175 ): 176 yield x 177 elif checkdirname(f, searchproject + "-iOS.appiconset"): 178 os.rename( 179 fullpath, os.path.join(dir, replaceproject + "-iOS.appiconset") 180 ) 181 fullpath = os.path.join(dir, replaceproject + "-iOS.appiconset") 182 183 print("recursing in -iOS.appiconset directory: ") 184 elif checkdirname(f, searchproject + "-macOS.appiconset"): 185 os.rename( 186 fullpath, os.path.join(dir, replaceproject + "-macOS.appiconset") 187 ) 188 fullpath = os.path.join(dir, replaceproject + "-macOS.appiconset") 189 190 print("recursing in -macOS.appiconset directory: ") 191 for x in dirwalk( 192 fullpath, 193 searchproject, 194 replaceproject, 195 searchman, 196 replaceman, 197 oldroot, 198 newroot, 199 ): 200 yield x 201 elif f in SUBFOLDERS_TO_SEARCH: 202 print("recursing in " + f + " directory: ") 203 for x in dirwalk( 204 fullpath, 205 searchproject, 206 replaceproject, 207 searchman, 208 replaceman, 209 oldroot, 210 newroot, 211 ): 212 yield x 213 214 if os.path.isfile(fullpath): 215 filename = os.path.basename(fullpath) 216 newfilename = filename.replace(searchproject, replaceproject) 217 base, extension = os.path.splitext(filename) 218 219 if not (extension in FILTERED_FILE_EXTENSIONS) and not ( 220 filename in FILTERED_FILE_NAMES 221 ): 222 223 print("Replacing project name strings in file " + filename) 224 replacestrs(fullpath, searchproject, replaceproject) 225 226 print("Replacing captitalized project name strings in file " + filename) 227 replacestrs(fullpath, searchproject.upper(), replaceproject.upper()) 228 229 print("Replacing manufacturer name strings in file " + filename) 230 replacestrs(fullpath, searchman, replaceman) 231 232 if oldroot and newroot: 233 print("Replacing iPlug2 root folder in file " + filename) 234 replacestrs(fullpath, oldroot, newroot) 235 replacestrs( 236 fullpath, oldroot.replace("/", "\\"), newroot.replace("/", "\\") 237 ) 238 239 else: 240 print("NOT replacing name strings in file " + filename) 241 242 if filename != newfilename: 243 print("Renaming file " + filename + " to " + newfilename) 244 os.rename(fullpath, os.path.join(dir, newfilename)) 245 246 yield f, fullpath 247 else: 248 yield f, fullpath 249 250 251 def main(): 252 global VERSION 253 print( 254 "\nIPlug Project Duplicator v" 255 + VERSION 256 + " by Oli Larkin ------------------------------\n" 257 ) 258 259 numargs = len(sys.argv) - 1 260 261 if not (numargs == 3 or numargs == 4): 262 print( 263 "Usage: duplicate.py inputprojectname outputprojectname manufacturername (outputprojectpath)" 264 ) 265 sys.exit(1) 266 else: 267 inputprojectname = sys.argv[1] 268 outputprojectname = sys.argv[2] 269 manufacturer = sys.argv[3] 270 271 if numargs == 4: 272 outputbasepath = os.path.abspath(sys.argv[4]) 273 else: 274 outputbasepath = os.getcwd() 275 276 if not (os.path.isdir(outputbasepath)): 277 print("error: Output path does not exist") 278 sys.exit(1) 279 280 outputpath = os.path.join(outputbasepath, outputprojectname) 281 282 if " " in inputprojectname: 283 print("error: input project name has spaces") 284 sys.exit(1) 285 286 if inputprojectname not in os.listdir(os.curdir): 287 print( 288 "error: input project " 289 + inputprojectname 290 + " doesn't exist, check spelling/case?" 291 ) 292 sys.exit(1) 293 294 if " " in outputprojectname: 295 print("error: output project name has spaces") 296 sys.exit(1) 297 298 if " " in manufacturer: 299 print("error: manufacturer name has spaces") 300 sys.exit(1) 301 302 # remove a trailing slash if it exists 303 if inputprojectname[-1:] == "/": 304 inputprojectname = inputprojectname[0:-1] 305 306 if outputprojectname[-1:] == "/": 307 outputprojectname = outputprojectname[0:-1] 308 309 # check that the folders are OK 310 if os.path.isdir(inputprojectname) == False: 311 print("error: input project not found") 312 sys.exit(1) 313 314 if os.path.isdir(outputpath): 315 print("error: output project allready exists") 316 sys.exit(1) 317 # rmtree(output) 318 319 print("copying " + inputprojectname + " folder to " + outputpath) 320 copytree(inputprojectname, outputpath, ignore=ignore_patterns(*DONT_COPY)) 321 322 oldroot = "" 323 newroot = "" 324 325 if numargs == 4: 326 configpath = os.path.join(inputprojectname, "config") 327 xcconfig = parse_xcconfig(configpath + "/" + inputprojectname + "-mac.xcconfig") 328 oldroot = xcconfig["IPLUG2_ROOT"] 329 iplug2folder = os.path.abspath(os.path.join(configpath, oldroot)) 330 newroot = os.path.relpath(iplug2folder, os.path.join(outputpath, "config")) 331 else: 332 newroot = "" 333 334 # replace manufacturer name strings 335 for dir in dirwalk( 336 outputpath, 337 inputprojectname, 338 outputprojectname, 339 "AcmeInc", 340 manufacturer, 341 oldroot, 342 newroot, 343 ): 344 pass 345 346 # replace project name in root 347 for dir in dirwalk( 348 scriptpath, 349 inputprojectname, 350 outputprojectname, 351 "AcmeInc", 352 manufacturer, 353 oldroot, 354 newroot, 355 ): 356 pass 357 358 # replace project name in github 359 for dir in dirwalk( 360 scriptpath + "/.github/workflows", 361 inputprojectname, 362 outputprojectname, 363 "AcmeInc", 364 manufacturer, 365 oldroot, 366 newroot, 367 ): 368 pass 369 370 # replace project name in vscode 371 for dir in dirwalk( 372 scriptpath + "/.vscode", 373 inputprojectname, 374 outputprojectname, 375 "AcmeInc", 376 manufacturer, 377 oldroot, 378 newroot, 379 ): 380 pass 381 382 # print("\ncopying gitignore template into project folder\n") 383 384 # copy('gitignore_template', outputpath + "/.gitignore") 385 386 config = parse_config(outputpath) 387 388 config["PLUG_UNIQUE_ID"] = randomFourChar() 389 390 set_uniqueid(outputpath, config["PLUG_UNIQUE_ID"]) 391 392 pp = pprint.PrettyPrinter(indent=4) 393 pp.pprint(config) 394 395 print("\ndone - don't forget to change PLUG_MFR_UID in config.h") 396 397 398 if __name__ == "__main__": 399 main()