From 9fa6e2082404b8330cec7c34e7ba18f98baf98d1 Mon Sep 17 00:00:00 2001 From: Trilarion Date: Fri, 9 Aug 2019 18:25:59 +0200 Subject: [PATCH] a few more conversions --- .gitignore | 1 + docs/data.json | 4 +- games/_all.md | 2 +- games/_puzzle.md | 2 +- games/fish_fillets_ng.md | 4 +- games/gltron.md | 2 +- statistics.md | 4 +- tools/archives.json | 3 + .../dfend_reloaded_source_releases_to_git.py | 49 +-------------- tools/git_statistics.py | 41 ++++++++++++ tools/maintenance.py | 33 +++++++++- tools/utils/utils.py | 62 ++++++++++++++++++- 12 files changed, 148 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index a8424c53..d505e3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /.idea /tools/archive/** /tools/conversion/** +/tools/git_repositories.json __pycache__ /is_already_included.txt /dismissed.txt diff --git a/docs/data.json b/docs/data.json index 25c98a04..56aff7c9 100644 --- a/docs/data.json +++ b/docs/data.json @@ -1180,7 +1180,7 @@ "Fish Fillets - Next Generation (home, entry)", "Port of the wonderful puzzle game Fish Fillets from ALTAR..", "Link", - "mature / inactive since 2011", + "mature / inactive since 2014", "puzzle, port", "Source - C++ - GPL-2.0" ], @@ -1398,7 +1398,7 @@ "Link", "beta / inactive since 2017", "action, snake-like", - "Source - C - GPL" + "Source - C - GPL" ], [ "GM Tools (home, entry)", diff --git a/games/_all.md b/games/_all.md index 270b19c7..8929f326 100644 --- a/games/_all.md +++ b/games/_all.md @@ -147,7 +147,7 @@ - **[Fallen Spire](fallen_spire.md)** (Python, GPL-3.0, beta, inactive since 2009) - **[Fanwor](fanwor.md)** (C, GPL-2.0, mature) - **[First Strike](first_strike.md)** (Java, MIT, mature) -- **[Fish Fillets - Next Generation](fish_fillets_ng.md)** (C++, GPL-2.0, mature, inactive since 2011) +- **[Fish Fillets - Next Generation](fish_fillets_ng.md)** (C++, GPL-2.0, mature, inactive since 2014) - **[Flare Engine](flare_engine.md)** (C++, GPL-3.0, mature) - **[FlightGear](flightgear.md)** (C++, GPL-2.0, mature) - **[Flixel](flixel.md)** (ActionScript, MIT, mature) diff --git a/games/_puzzle.md b/games/_puzzle.md index efcce56e..7a5a1ecf 100644 --- a/games/_puzzle.md +++ b/games/_puzzle.md @@ -9,7 +9,7 @@ - **[BlockOut II](blockout_ii.md)** (C++, GPL-2.0, mature, inactive since 2014) - **[Brain Workshop](brain_workshop.md)** (Python, GPL, mature, inactive since 2011) - **[Enigma](enigma.md)** (C, C++, GPL-2.0, mature) -- **[Fish Fillets - Next Generation](fish_fillets_ng.md)** (C++, GPL-2.0, mature, inactive since 2011) +- **[Fish Fillets - Next Generation](fish_fillets_ng.md)** (C++, GPL-2.0, mature, inactive since 2014) - **[Frozen Bubble](frozen_bubble.md)** (Perl, GPL-2.0, mature, inactive since 2012) - **[Grabble](grabble.md)** (Java, ?, mature, inactive since 2006) - **[HoDoKu](hodoku.md)** (Java, GPL-3.0, mature, inactive since 2013) diff --git a/games/fish_fillets_ng.md b/games/fish_fillets_ng.md index 59c3cc87..9a6a6dfb 100644 --- a/games/fish_fillets_ng.md +++ b/games/fish_fillets_ng.md @@ -4,11 +4,11 @@ _Port of the wonderful puzzle game Fish Fillets from ALTAR interactive._ - Home: http://fillets.sourceforge.net/, https://sourceforge.net/projects/fillets/ - Media: https://en.wikipedia.org/wiki/Fish_Fillets_NG -- State: mature, inactive since 2011 +- State: mature, inactive since 2014 - Download: http://fillets.sourceforge.net/download.php - Platform: Windows, Linux, macOS - Keywords: puzzle, port -- Code repository: https://git.code.sf.net/p/fillets/code-fillets-ng, http://fillets.cvs.sourceforge.net (cvs) +- Code repository: https://git.code.sf.net/p/fillets/code-fillets-ng, https://git.code.sf.net/p/fillets/code-fillets_data (+), https://git.code.sf.net/p/fillets/code-fillets_web (+), http://fillets.cvs.sourceforge.net (cvs) - Code language: C++ - Code license: GPL-2.0 - Code dependencies: SDL diff --git a/games/gltron.md b/games/gltron.md index 5658f29c..0636a918 100644 --- a/games/gltron.md +++ b/games/gltron.md @@ -8,7 +8,7 @@ _3D snake game based on the light cycle portion of the film Tron._ - Download: http://www.gltron.org/download.php - Platform: Windows, Linux, macOS - Keywords: action, snake-like -- Code repository: https://git.code.sf.net/p/gltron/git, https://svn.code.sf.net/p/gltron/code (svn), http://gltron.cvs.sourceforge.net (cvs) +- Code repository: https://github.com/Trilarion/gltron.git, https://git.code.sf.net/p/gltron/git (+), https://svn.code.sf.net/p/gltron/code (svn), http://gltron.cvs.sourceforge.net (cvs) - Code language: C - Code license: GPL - Code dependencies: SDL diff --git a/statistics.md b/statistics.md index 6da708c5..5a57679f 100644 --- a/statistics.md +++ b/statistics.md @@ -1,7 +1,7 @@ [comment]: # (autogenerated content, do not edit) # Statistics -analyzed 518 entries on 2019-08-08 15:17:51 +analyzed 518 entries on 2019-08-09 17:19:38 ## State @@ -11,7 +11,7 @@ analyzed 518 entries on 2019-08-08 15:17:51 ##### Inactive State -Blobby Volley 2 (2017), Eat The Whistle (2017), GLtron (2017), PokerTH (2017), Scrolling Game Development Kit 2 (2017), Tressette (2017), YSoccer (2017), Zone of Control (2017), 3d.city (2016), Atlantis (2016), Atomic Tanks (2016), Atrinik (2016), Birth of the Empires (2016), DNT (2016), Dark Destiny (2016), Dungeon Monkey Eternal (2016), FreeRCT (2016), Infiniminer (2016), JaNaG - Java Name Generator (2016), Mechanized Assault & eXploration Reloaded (2016), Open Yahtzee (2016), Polis (2016), TORCS, The Open Racing Car Simulator (2016), Tremulous (2016), ransack (2016), Aleph One: Marathon (2015), Atomiks (2015), Battleround (2015), Blobwars: Metal Blob Solid (2015), Boulder Dash (2015), D-Fend Reloaded (2015), Dash Engine (2015), DeSmuME (2015), Delta Engine (2015), Egoboo (2015), Free heroes2 engine (2015), Liquid War (2015), M.E.W.L. (2015), Roguish (2015), Scrabble3D (2015), Tenes Empanadas Graciela (2015), The Endless Dungeons (2015), The Epic of Heroes (2015), TwinEngine (2015), Witch Blast (2015), pyORPG (2015), Argentum Online (2014), Battles of Antargis (2014), BlockOut II (2014), Cart Life (2014), Deity (2014), Dune Dynasty (2014), EternalWinterWars (2014), FAR Colony (2014), Fujo (2014), Grobots (2014), Hale (2014), Heroes of Wing Commander (2014), Kingdoms (2014), Lips of Suna (2014), Open RPG Maker (2014), Open Tibia (2014), Radakan (2014), SDL Game Engine 2D (2014), SDL Sopwith (2014), Scorched 3D (2014), Sintel The Game (2014), Summoning Wars (2014), Supremacy (2014), Turious (2014), VDrift (2014), X-Moto (2014), Xenowar (2014), rpge (2014), sandbox Game Maker (2014), Bos Wars (2013), C-evo (2013), Candy Box 2 (2013), Decker (2013), DemiGod (2013), Dungeon Mapper (2013), HoDoKu (2013), HolySpirit (2013), MechCommander 2 Omnitech (2013), Mpango (2013), Murder In The Public Domain (2013), OpenRPG (2013), Phantasy Star Rebirth (2013), Room for Change (2013), SoftPixel Engine (2013), Source of Tales (2013), The Bub's Brothers (2013), Trinity Reign (2013), Zero Ballistics (2013), Biniax (2012), BlackNova Traders (2012), Blitzkrieg (2012), Cataclysm (2012), Celestron (2012), CommandoJS (2012), Conquests (2012), DarkCity (2012), Frozen Bubble (2012), Goblin Camp (2012), Hexwar (2012), Mega Mario (2012), OpenArena (2012), PARPG (2012), TROPHY (2012), Thousand Parsec (2012), Tux Football (2012), UFO2000 (2012), Wizards Magic (2012), Aeron (2011), Battlefield Java (2011), Brain Workshop (2011), Danger from the Deep (2011), Dawn (2011), Fish Fillets - Next Generation (2011), GalaxyMage Redux (2011), KQ Lives (2011), Kobold's Quest 2 (2011), OpenBlox (2011), OpenMOO2 (2011), PyKaraoke (2011), Skrupel - Tribute Compilation (2011), Smash Battle (2011), Song of Albion (2011), Star Control II: The Ur-Quan Masters (2011), Tux of Math Command (2011), UlDunAd (2011), World of Phaos (2011), X-Force: Fight For Destiny (2011), AI Wars (2010), Bombermaaan (2010), Crimson Fields (2010), Dragon History - Dračí Historie (2010), Heroes of Wesnoth (2010), Labyrinth of Worlds (2010), Linwarrior 3D (2010), Mercenary Commander (2010), OpenHoMM (2010), Slay (2010), SpaceTrader for Java (2010), UltraStar (2010), XPilot (2010), XSera (2010), nXtank (2010), Alien Assault Traders (2009), Annchienta (2009), Ardentryst (2009), Battle Tanks (2009), Crown and Cutlass (2009), Dark Oberon (2009), Duel Commander (2009), Fall of Imyrin (2009), Fallen Spire (2009), FreeTrain (2009), Glest (2009), Goblin Hack (2009), MicroWar 2.0 (2009), Netrek (2009), ORIENT (2009), SDL Asylum (2009), Secret Mario Chronicles (2009), Space Trader for Windows (2009), World of Heroes (2009), Yo Frankie! (2009), A Planet's Revenge (2008), Attal: Lords of doom (2008), Avanor (2008), Freestars (2008), Mars, Land of No Mercy (2008), Meritous (2008), Open Game Engine (2008), S.C.O.U.R.G.E. (2008), Sengoku: Warring States of Japan (2008), Space Opera (2008), Armies (2007), Brutal Chess (2007), Eos, Dawn of Light: A Space Opera (2007), Pang Zero (2007), SharpKonquest (2007), Silvertree (2007), Slash'EM (2007), Underworld Adventures (2007), World Builder (2007), kiki the nano bot (2007), Betrayer's Moon Tactics (2006), Boson (2006), GPL Arcade Volleyball (2006), GUSANOS (2006), Grabble (2006), JQuest (2006), Linley's Dungeon Crawl (2006), Metal Mech (2006), RPDungeon - computer aided role playing (2006), Rogue Clone IV (2006), StarBlastrix (2006), GalaxyNG (2005), H-World (2005), Lincity (2005), Spice Trade (2005), Tumiki Fighters (2005), WAtomic (2005), Xconq (2005), ZAngband (2005), Colonization too (2004), GM Tools (2004), Gee Whiz (2004), Openglad (2004), PySol (2004), T-Bots (2004), AntiChess (2003), Cat Mother Dead Justice (2003), Civil (2003), Machinations (2003), Pizza Business (2003), Planetary Hoppers (2003), The Clans (2003), Wargamer (2003), XArchon (2003), Maelstrom (2002), Umbra (2002), Greenius' Civil War (2001), Tux Racer (2001), Operation Citadel (2000), xdigger (1999), Ballerburg (1987) +Blobby Volley 2 (2017), Eat The Whistle (2017), GLtron (2017), PokerTH (2017), Scrolling Game Development Kit 2 (2017), Tressette (2017), YSoccer (2017), Zone of Control (2017), 3d.city (2016), Atlantis (2016), Atomic Tanks (2016), Atrinik (2016), Birth of the Empires (2016), DNT (2016), Dark Destiny (2016), Dungeon Monkey Eternal (2016), FreeRCT (2016), Infiniminer (2016), JaNaG - Java Name Generator (2016), Mechanized Assault & eXploration Reloaded (2016), Open Yahtzee (2016), Polis (2016), TORCS, The Open Racing Car Simulator (2016), Tremulous (2016), ransack (2016), Aleph One: Marathon (2015), Atomiks (2015), Battleround (2015), Blobwars: Metal Blob Solid (2015), Boulder Dash (2015), D-Fend Reloaded (2015), Dash Engine (2015), DeSmuME (2015), Delta Engine (2015), Egoboo (2015), Free heroes2 engine (2015), Liquid War (2015), M.E.W.L. (2015), Roguish (2015), Scrabble3D (2015), Tenes Empanadas Graciela (2015), The Endless Dungeons (2015), The Epic of Heroes (2015), TwinEngine (2015), Witch Blast (2015), pyORPG (2015), Argentum Online (2014), Battles of Antargis (2014), BlockOut II (2014), Cart Life (2014), Deity (2014), Dune Dynasty (2014), EternalWinterWars (2014), FAR Colony (2014), Fish Fillets - Next Generation (2014), Fujo (2014), Grobots (2014), Hale (2014), Heroes of Wing Commander (2014), Kingdoms (2014), Lips of Suna (2014), Open RPG Maker (2014), Open Tibia (2014), Radakan (2014), SDL Game Engine 2D (2014), SDL Sopwith (2014), Scorched 3D (2014), Sintel The Game (2014), Summoning Wars (2014), Supremacy (2014), Turious (2014), VDrift (2014), X-Moto (2014), Xenowar (2014), rpge (2014), sandbox Game Maker (2014), Bos Wars (2013), C-evo (2013), Candy Box 2 (2013), Decker (2013), DemiGod (2013), Dungeon Mapper (2013), HoDoKu (2013), HolySpirit (2013), MechCommander 2 Omnitech (2013), Mpango (2013), Murder In The Public Domain (2013), OpenRPG (2013), Phantasy Star Rebirth (2013), Room for Change (2013), SoftPixel Engine (2013), Source of Tales (2013), The Bub's Brothers (2013), Trinity Reign (2013), Zero Ballistics (2013), Biniax (2012), BlackNova Traders (2012), Blitzkrieg (2012), Cataclysm (2012), Celestron (2012), CommandoJS (2012), Conquests (2012), DarkCity (2012), Frozen Bubble (2012), Goblin Camp (2012), Hexwar (2012), Mega Mario (2012), OpenArena (2012), PARPG (2012), TROPHY (2012), Thousand Parsec (2012), Tux Football (2012), UFO2000 (2012), Wizards Magic (2012), Aeron (2011), Battlefield Java (2011), Brain Workshop (2011), Danger from the Deep (2011), Dawn (2011), GalaxyMage Redux (2011), KQ Lives (2011), Kobold's Quest 2 (2011), OpenBlox (2011), OpenMOO2 (2011), PyKaraoke (2011), Skrupel - Tribute Compilation (2011), Smash Battle (2011), Song of Albion (2011), Star Control II: The Ur-Quan Masters (2011), Tux of Math Command (2011), UlDunAd (2011), World of Phaos (2011), X-Force: Fight For Destiny (2011), AI Wars (2010), Bombermaaan (2010), Crimson Fields (2010), Dragon History - Dračí Historie (2010), Heroes of Wesnoth (2010), Labyrinth of Worlds (2010), Linwarrior 3D (2010), Mercenary Commander (2010), OpenHoMM (2010), Slay (2010), SpaceTrader for Java (2010), UltraStar (2010), XPilot (2010), XSera (2010), nXtank (2010), Alien Assault Traders (2009), Annchienta (2009), Ardentryst (2009), Battle Tanks (2009), Crown and Cutlass (2009), Dark Oberon (2009), Duel Commander (2009), Fall of Imyrin (2009), Fallen Spire (2009), FreeTrain (2009), Glest (2009), Goblin Hack (2009), MicroWar 2.0 (2009), Netrek (2009), ORIENT (2009), SDL Asylum (2009), Secret Mario Chronicles (2009), Space Trader for Windows (2009), World of Heroes (2009), Yo Frankie! (2009), A Planet's Revenge (2008), Attal: Lords of doom (2008), Avanor (2008), Freestars (2008), Mars, Land of No Mercy (2008), Meritous (2008), Open Game Engine (2008), S.C.O.U.R.G.E. (2008), Sengoku: Warring States of Japan (2008), Space Opera (2008), Armies (2007), Brutal Chess (2007), Eos, Dawn of Light: A Space Opera (2007), Pang Zero (2007), SharpKonquest (2007), Silvertree (2007), Slash'EM (2007), Underworld Adventures (2007), World Builder (2007), kiki the nano bot (2007), Betrayer's Moon Tactics (2006), Boson (2006), GPL Arcade Volleyball (2006), GUSANOS (2006), Grabble (2006), JQuest (2006), Linley's Dungeon Crawl (2006), Metal Mech (2006), RPDungeon - computer aided role playing (2006), Rogue Clone IV (2006), StarBlastrix (2006), GalaxyNG (2005), H-World (2005), Lincity (2005), Spice Trade (2005), Tumiki Fighters (2005), WAtomic (2005), Xconq (2005), ZAngband (2005), Colonization too (2004), GM Tools (2004), Gee Whiz (2004), Openglad (2004), PySol (2004), T-Bots (2004), AntiChess (2003), Cat Mother Dead Justice (2003), Civil (2003), Machinations (2003), Pizza Business (2003), Planetary Hoppers (2003), The Clans (2003), Wargamer (2003), XArchon (2003), Maelstrom (2002), Umbra (2002), Greenius' Civil War (2001), Tux Racer (2001), Operation Citadel (2000), xdigger (1999), Ballerburg (1987) ## Code Languages diff --git a/tools/archives.json b/tools/archives.json index 63e7eec2..af4928c5 100644 --- a/tools/archives.json +++ b/tools/archives.json @@ -27,6 +27,8 @@ "https://git.code.sf.net/p/epicheroes/code", "https://git.code.sf.net/p/erebusrpg/code", "https://git.code.sf.net/p/fillets/code-fillets-ng", + "https://git.code.sf.net/p/fillets/code-fillets_data", + "https://git.code.sf.net/p/fillets/code-fillets_web", "https://git.code.sf.net/p/flightgear/flightgear", "https://git.code.sf.net/p/freecol/git", "https://git.code.sf.net/p/freelords/git", @@ -144,6 +146,7 @@ "https://github.com/TVTower/TVTower.git", "https://github.com/TobiasBielefeld/Simple-Solitaire.git", "https://github.com/Trilarion/D-Fend-Reloaded.git", + "https://github.com/Trilarion/gltron.git", "https://github.com/Trilarion/mpango.git", "https://github.com/Trilarion/scorched3d.git", "https://github.com/Trilarion/spacetraderjava.git", diff --git a/tools/conversions/dfend_reloaded_source_releases_to_git.py b/tools/conversions/dfend_reloaded_source_releases_to_git.py index e76e0c61..ab406f6b 100644 --- a/tools/conversions/dfend_reloaded_source_releases_to_git.py +++ b/tools/conversions/dfend_reloaded_source_releases_to_git.py @@ -3,13 +3,9 @@ Converts the source releases of D-Fend Reloaded to a Git. """ import sys -import os -import shutil -import zipfile import datetime -import subprocess import re -import time +from utils.utils import * def subprocess_run(cmd): @@ -24,32 +20,6 @@ def subprocess_run(cmd): else: print(' output: {}'.format(result.stdout.decode('ascii'))) - -def unzip(zip_file, destination_directory): - dirs = {} - - with zipfile.ZipFile(zip_file, 'r') as zip: - for info in zip.infolist(): - name, date_time = info.filename, info.date_time - name = os.path.join(destination_directory, name) - zip.extract(info, destination_directory) - - # still need to adjust the dt o/w item will have the current dt - date_time = time.mktime(info.date_time + (0, 0, -1)) - - if os.path.isdir(name): - # changes to dir dt will have no effect right now since files are - # being created inside of it; hold the dt and apply it later - dirs[name] = date_time - else: - os.utime(name, (date_time, date_time)) - - # done creating files, now update dir dt - for name in dirs: - date_time = dirs[name] - os.utime(name, (date_time, date_time)) - - def single_release(zip): """ @@ -106,23 +76,6 @@ def single_release(zip): subprocess_run(['git', 'commit', '--message={}'.format(message), '--author={}'.format(author), '--date={}'.format(original_date)]) -def recreate_directory(path): - """ - - """ - if os.path.isdir(path): - shutil.rmtree(path) - for attempts in range(10): - try: - os.mkdir(path) - except PermissionError: - time.sleep(0.1) - continue - else: - break - else: - raise RuntimeError() - if __name__ == "__main__": # general properties diff --git a/tools/git_statistics.py b/tools/git_statistics.py index fbfd41f8..a9ce4ab6 100644 --- a/tools/git_statistics.py +++ b/tools/git_statistics.py @@ -7,3 +7,44 @@ takes all gits that we have in the list and checks the master branch out, then c uses git log --format="%an, %at, %cn, %ct" --all ti get commits, committers and times (as unix time stamp) """ + +import json +from utils.utils import * + +if __name__ == "__main__": + + # paths + file_path = os.path.realpath(os.path.dirname(__file__)) + archives_path = os.path.join(file_path, 'git_repositories.json') + temp_path = os.path.join(file_path, 'temp') + + # get git archives + text = read_text(archives_path) + archives = json.loads(text) + print('process {} git archives'.format(len(archives))) + + # loop over them + for count, archive in enumerate(archives, 1): + + # printer iteration info + print('{}/{} - {}'.format(count, len(archives), archive)) + + # recreate temp folder + recreate_directory(temp_path) + os.chdir(temp_path) + + # clone git in temp folder + subprocess_run(["git", "clone", "--mirror", archive, temp_path]) + + # get commits, etc. info + info = subprocess_run(["git", "log", '--format="%an, %at, %cn, %ct"']) + + info = info.split('\n') + info = info[:-1] # last line is empty + number_commits = len(info) + + info = [x.split(', ') for x in info] + commiters = set([x[0] for x in info]) + + print(' commits: {}, commiters {}'.format(number_commits, len(commiters))) + diff --git a/tools/maintenance.py b/tools/maintenance.py index eb2db341..57b77498 100644 --- a/tools/maintenance.py +++ b/tools/maintenance.py @@ -822,8 +822,8 @@ def export_primary_code_repositories_json(): unconsumed_entries = [] # for every entry filter those that are known git repositories (add additional repositories) + field = 'code repository-raw' for info in infos: - field = 'code repository-raw' # if field 'Code repository' is available if field in info: consumed = False @@ -878,6 +878,34 @@ def export_primary_code_repositories_json(): write_text(json_path, text) +def export_git_code_repositories_json(): + """ + + """ + + urls = [] + field = 'code repository' + + # for every entry, get all git + for info in infos: + # if field 'Code repository' is available + if field in info: + repos = info[field] + if repos: + # take the first + repo = repos[0] + url = git_repo(repo) + if url: + urls.append(url) + + # sort them alphabetically (and remove duplicates) + urls.sort() + + # write them to tools/git + json_path = os.path.join(root_path, 'tools', 'git_repositories.json') + text = json.dumps(urls, indent=1) + write_text(json_path, text) + if __name__ == "__main__": # paths @@ -905,5 +933,8 @@ if __name__ == "__main__": # collect list of primary code repositories export_primary_code_repositories_json() + # collect list of git code repositories (only one per project) for git_statistics script + # export_git_code_repositories_json() + # check external links (only rarely) # check_validity_external_links() diff --git a/tools/utils/utils.py b/tools/utils/utils.py index 14cacc5d..ffd5ed5a 100644 --- a/tools/utils/utils.py +++ b/tools/utils/utils.py @@ -9,6 +9,8 @@ import tarfile import time import urllib.request import zipfile +import errno +import stat def read_text(file): @@ -194,6 +196,14 @@ def download_url(url, destination): shutil.copyfileobj(response, f) +def handleRemoveReadonly(func, path, exc): + """ + Necessary on Windows. See https://stackoverflow.com/questions/1889597/deleting-directory-in-python + """ + os.chmod(path, stat.S_IWRITE) + func(path) + + def git_clear_path(git_path): """ Clears all in a path except the '.git' directory @@ -204,6 +214,56 @@ def git_clear_path(git_path): continue item = os.path.join(git_path, item) if os.path.isdir(item): - shutil.rmtree(item) + shutil.rmtree(item, onerror=handleRemoveReadonly) else: os.remove(item) + + +def recreate_directory(path): + """ + Recreates a directory (deletes before if existing) + """ + if os.path.isdir(path): + shutil.rmtree(path, onerror=handleRemoveReadonly) + for attempts in range(10): + try: + os.mkdir(path) + except PermissionError: + time.sleep(0.1) + continue + else: + break + else: + raise RuntimeError() + + +def unzip(zip_file, destination_directory): + """ + Unzips and keeps the original modified date. + + :param zip_file: + :param destination_directory: + :return: + """ + dirs = {} + + with zipfile.ZipFile(zip_file, 'r') as zip: + for info in zip.infolist(): + name, date_time = info.filename, info.date_time + name = os.path.join(destination_directory, name) + zip.extract(info, destination_directory) + + # still need to adjust the dt o/w item will have the current dt + date_time = time.mktime(info.date_time + (0, 0, -1)) + + if os.path.isdir(name): + # changes to dir dt will have no effect right now since files are + # being created inside of it; hold the dt and apply it later + dirs[name] = date_time + else: + os.utime(name, (date_time, date_time)) + + # done creating files, now update dir dt + for name in dirs: + date_time = dirs[name] + os.utime(name, (date_time, date_time)) \ No newline at end of file