/usr/bin/garchive is in geda-utils 1:1.6.2-3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | #! /usr/bin/env python
#
# Copyright (C) 2003 Stuart Brorson <sdb@cloud9.net>
#
#------------------------------------------------------------------
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#-------------------------------------------------------------------
"""
This program is used to create a gEDA design archive. It operates in two
modes: archive mode and extract mode. In archive mode it creates a
project archive from a bunch of project files, and in extract mode it
extracts the files from the archive and places them in the local dir.
Detailed description:
Information about program invocation is held in the Usage string below.
--- Archive mode algorithm:
1. It gets the local directory name, as well as a bunch of info from the
command line & stores all the info in the object "Args". Then it
cd's into /tmp (ScratchDirectory).
2. It gets the symbol library search path from $(/usr/share/gEDA)/
gschemrc-common and ./gschemrc & creates a list of all search
paths. Note that the system-dependent search path is hardcoded into
the script by "make" when the file is installed.
3. It reads the list of files to archive from ./garchiverc (or the -f
substitute) and the command line and creates an internal list of files to
archive.
4. It finds the .sch files among the archive list, and creates an internal
list of schem files process/archive.
5. For each schem file in the list, it opens the file, runs through it,
and builds a list of symbols used in that file. Naturally, duplicate
symbols are ignored.
6. It opens a directory called /tmp/garchive-symbols. For each symbol
file in the symbol file list, it gets the file from $(/usr/share/gEDA)/sym
and sticks it into ./garchive-symbols.
7. It takes the local gschemrc, and munges it so that gschem will find
all symbols in ./garchive-symbols.
8. It then creates a tar archive of the following:
* All files listed in garchiverc and/or the command line.
* The entire ./garchive-symbols directory
* gschemrc
* garchiverc
9. The prog then gzips the tar archive, renames it to the name
specified by the user, and sticks it in the user's directory
10. It then cd's back to the local directory & deletes the leftover
cruft from /tmp (or ScratchDirectory).
Important data structures during creation of archive:
* LibraryPathList -- list of paths to symbol libraries.
* ArchiveFileList -- list of all files to archive. Includes gschemrc and
garchiverc, as well as garchive-symbols/
* SchemFileList -- list of schematic files found.
* SymbolFileList -- list of symbol files found. Duplicates are ignored.
--- Extract mode algorithm:
1. Copy archive file into /tmp (or ScratchDirectory).
2. Create a list of archive's contents using "tar -t -f ProjectArchive"
3. Extract files into /tmp
3. Loop on file list. Move each file into user's directory.
Before each move, make sure that no overwrite of existing files will occur.
After each iteration, clean up the cruft left in /tmp.
Note: File names used internally have no / prefix. Dir names have no / suffix.
Therefore, must include / manually in each case.
--- TBD suggestions from users:
None right now . . . .
--- Revision history:
20031114 -- First (alpha) version by SDB.
20031121 -- Incorporated SPICE file archiving. Now get /tmp dir from
environment. Presence of RC files is now optional -- user
is queried about creating them if they don't exist.
20031204 -- Changed program so that it keeps .tar.gz as the archive file
suffix due to popular demand.
"""
############################################################################
import sys, copy, string, getopt, re, os, commands
############################################################################
# Helper fcns and data structures. #
############################################################################
#---------------------------------------------------------------------------
# This is the help string.
Usage =\
"""
garchive -- the gEDA archiving utility. Used to create as well as extract
gEDA designs from an archive. The two modes of operation are "archive mode"
(archive creation) and "extract mode". Archive mode is the default.
Command line switches:
-f <filename> -- Optional. Used in archive mode. Read files to archive from
<filename> instead of garchiverc.
-v -- Optional. Verbose mode. Used in both archive and extract mode.
Spews lots of info about what the prog is doing.
-e -- Mandatory if you want to extract. Extract mode.
Open up the archive specified on the command line.
-a -- Optional. Archive mode. Archive mode (i.e. create a project
archive) is the default; this flag exists to give people
the warm and fuzzies.
-o <outfile> -- Optional. Used in archive mode. Specifies the name of
the output archive file. The output file extension
should be ".tar.gz". If this flag is not specified, the
output file name is "ProjectArchive.tar.gz".
Example usage:
Create an archive named MyArchive.tar.gz (files to store listed in garchiverc):
garchive -o MyArchive.tar.gz
Verbosely create an archive (archives files listed on cmd line
as well as those listed in garchiverc):
garchive -v -o MyArchive.tar.gz README Schematic1.sch Schematic2.sch Schematic3.sch
Extract an archive:
garchive -e ProjectArchive.tar.gz
Copyright (C) 2003 by SDB. Released under the GPL.
"""
#---------------------------------------------------------------------------
def DebugSpew(Args, String):
"""
This prints out String when the -v flag is set, otherwise is silent
"""
if (Args.VerboseMode == "verbose"):
print("---- "+ String)
return
#---------------------------------------------------------------------------
def CheckFilename(Filename):
"""
This checks a string to make sure that it is a valid filename.
It currently doesn't do very much. . . .
"""
if (re.search('\.tar\.gz$', Filename)):
return 1
else:
return 0
#----------------------------------------------------------------------
def NormalizePath(SearchDir, DirName):
"""
This fcn expands environment variables like ${GEDADATA} and ${HOME}
in full absolute file/directory names.
Environment vars must be in the form ${foo}.
It expects to see a directory or file name like "${foo}/bar/baz/".
Only one env var may be expanded at a time. SearchDir is the base
directory from which all relative paths are normalized.
"""
# First replace environment var
if re.match('\${[\w]+}', DirName):
Match = re.search('(\${)([\w]+)(}/)([\w/]+)', DirName)
EnvVar = Match.group(2)
# Need to make sure that something exists beyond ${ENVVAR}
try:
Remainder = Match.group(4)
except KeyError:
Remainder = ""
# Check if env variable is ${GEDADATA}. If so, just replace it with Args.GedaDataDir
if (EnvVar == "GEDADATA"):
EnvVar = Args.GedaDataDir
else:
# Try to get environment variable
try:
EnvVar = os.environ[EnvVar]
except KeyError:
print ("Env variable "+EnvVar+" not defined in current environment")
print ("Try setting it. . . .")
sys.exit(1)
DirName = EnvVar+"/"+Remainder
# Now cd into SearchDir and perform a filename normalization
# (to get rid of .. . and other relative file paths . . .)
# Then cd back.
CurrentDir = os.getcwd()
os.chdir(SearchDir)
DirName = os.path.abspath(DirName)
os.chdir(CurrentDir)
return DirName
#---------------------------------------------------------------------------
class CmdLineArgs:
"""
This class holds info about the environment and cmd line args passed to the
program. It has only one method: the constructor, which gets the args
and fills out the public vars. The public vars are:
ProgramMode = "archive", "extract"
OutputFileName (archive only) = the name of the archive. default = ProjectArchive.tar.gz
InputFileNames = [list of input files on command line]
RcFileName (archive only) = name of garchiverc to use (instead of garchiverc)
VerboseMode = "quiet", "verbose"
FilesToArchiveList (archive only)
UserDir = Directory holding files to archive. (Directory where garchive was invoked.)
ScratchDir = "/tmp" by default
FileArchiveDir = "gschem-files" by default
GedaDataDir = directory holding GEDA data & files such as "system-gafrc"
"""
def __init__(self):
"""
Constructor: parse through cmd line args and fill out vars.
"""
self.VerboseMode = "quiet" # default
self.ProgramMode = "archive" # default
self.GarchiveRcFileName = "garchiverc" # default
self.GschemRcFileName = "gschemrc" # default
self.OutputFileName = "ProjectArchive.tar.gz" # default
self.UserDir = os.path.abspath(os.getcwd())
self.FileArchiveDir = "gschem-files" # default
# Get GedaDataDir -- this will be set by the Makefile, which does
# an sed replacement of /usr/share/gEDA
self.GedaDataDir = "/usr/share/gEDA"
# self.GedaDataDir = "/home/binaries/geda/share/gEDA" # Used for debug
# Get ScratchDir, either from environment, or just use /tmp as default.
for EnvVar in ["TMP", "TMPVAR", "TEMP"]:
try:
TempDir = os.environ[EnvVar]
except:
continue # Not present, continue looping
else:
self.ScratchDir = TempDir # Got it!
break
else:
self.ScratchDir = "/tmp" # no env var set, use default
# Get and process command line args
try:
OptList, Args = getopt.getopt(sys.argv[1:], 'aef:ho:v')
except getopt.error:
print Usage # print out usage string if
# user uses invalid flag.
sys.exit(1)
# First pass through args. Get switch settings & set program modes.
for Option, Value in OptList:
if Option == '-a':
self.ProgramMode = "archive"
if Option == '-e':
self.ProgramMode = "extract"
if Option == '-v':
self.VerboseMode = "verbose"
if Option == '-h':
print Usage
sys.exit(0)
# Second pass. Do sanity checking and get configured filenames.
for Option, Value in OptList:
if Option == '-a':
if self.ProgramMode == "extract": # sanity check
raise SyntaxError("Incompatible command line args")
if Option == '-e':
if self.ProgramMode == "archive": # sanity check
raise SyntaxError("Incompatible command line args")
if Option == '-f':
if self.ProgramMode == "extract": # sanity check
raise SyntaxError("Incompatible command line args")
try:
os.stat(Value)
except OSError:
print("Resource file "+Value+" doesn't exist. Exiting.")
sys.exit(1)
else:
self.GarchiveRcFileName = Value #strcopy?
if Option == '-o':
if self.ProgramMode == "extract": # sanity check
raise SyntaxError("Incompatible command line args")
if CheckFilename(Value):
self.OutputFileName = Value #strcopy?
else:
print("Warning -- output file suffix is not \".tar.gz\" -- the")
print("extractor won't know how to deal with your archive.")
Input = raw_input("Continue? [y/N] ")
if ( (len(Input) == 0) or (Input[0] != "y") ):
sys.exit(1)
else:
self.OutputFileName = Value
# Third step: Create list of files remaining on command line, and create output
# base file name.
self.CmdLineFileList = Args
self.OutputFileNameBase = re.sub('\.tar\.gz', '', self.OutputFileName)
return
#---------------------------------------------------------------------------
def GetLibraryPath(Args):
"""
This fcn takes the library search path from the local dir and the system
gschem-gafrc.
"""
DebugSpew(Args, "Now in GetLibraryPath.")
LibraryPathList = []
LocalRCFileName = Args.UserDir+"/"+Args.GschemRcFileName
SystemRCFileName = Args.GedaDataDir+"/system-gafrc"
# Now read in system rc file and create sym lib path
DebugSpew(Args, "Processing system resource file "+SystemRCFileName)
try:
SysFile = open(SystemRCFileName, "r")
except:
print("Unable to find system resource file "+SystemRCFileName+".")
sys.exit(1)
for line in SysFile.readlines():
# Match "(component-library " string. . . .
if re.match('^\(component-library ', line):
Match = re.search('(")([{$}\w/]+)(")', line)
Dir = Match.group(2)
Dir = NormalizePath(Args.GedaDataDir, Dir) # Expand any env variables such as ${GEDADATA}. . .
# DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
LibraryPathList.append(Dir)
# Match "(component-library-search " string. . . .
if re.match('^\(component-library-search', line):
Match = re.search('(")([{$}\w/]+)(")', line)
Dir = Match.group(2)
Dir = NormalizePath(Args.GedaDataDir, Dir) # Expand any env variables such as ${GEDADATA}. . .
if Dir in LibraryPathList:
pass
else:
# DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
LibraryPathList.append(Dir)
SysFile.close()
# Next read in LocalRCFileName
DebugSpew(Args, "Processing local resource file "+LocalRCFileName)
try:
LocalFile = open(LocalRCFileName, "r")
except:
Input = raw_input(LocalRCFileName+" doesn't exist. Create empty version in local dir? [Y/n] ")
if ( (len(Input) == 0) or (Input[0] != "n") ):
os.system("touch "+LocalRCFileName)
else:
print("You need "+LocalRCFileName+" to create archive. Aborting.")
sys.exit(1)
for line in LocalFile.readlines():
if re.match('^\(component-library ', line):
Match = re.search('(")([\S]+)(")', line) # Note additional . to search for
Dir = Match.group(2)
Dir = NormalizePath(Args.UserDir, Dir) # Expand any env variables and ./
if Dir in LibraryPathList:
pass
else:
# DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
LibraryPathList.append(Dir)
LocalFile.close()
# Reverse list because that's how it is searched
LibraryPathList.reverse()
return LibraryPathList
#---------------------------------------------------------------------------
def CreateArchiveFileList(Args):
"""
This creates the list of files in the archive. It starts with
known files, and then adds the names of the files to archive,
given either at the command line or in the garchiverc file.
"""
DebugSpew(Args, "Now in CreateArchiveFileList.")
ArchFileList = []
# Start with known file names
PotentialArchFileList = [Args.UserDir+"/"+Args.GschemRcFileName, Args.UserDir+"/"+Args.GarchiveRcFileName] # Could use map here. . .
# Make sure each file exists and can be saved
for FileName in PotentialArchFileList:
if (os.path.isfile(FileName) or os.path.isdir(FileName)):
FileName = NormalizePath(Args.UserDir, FileName) # Just make sure filename is kosher. . . .
ArchFileList.append(FileName)
else:
Input = raw_input(FileName+" doesn't exist. Create empty version in local dir? [Y/n] ")
if ( (len(Input) == 0) or (Input[0] != "n") ):
print("Creating "+FileName+" in archive.")
os.system("touch "+FileName)
ArchFileList.append(FileName)
else:
print("You need "+FileName+" to create archive. Aborting.")
sys.exit(1)
# Add the gschem-files dir /tmp/gschem-files
ArchFileList.append(Args.ScratchDir+"/"+Args.FileArchiveDir) # We build the archive dir in /tmp
# Now get names of all schematics and other files to archive.
# First get file names from command line
DebugSpew(Args, "Examining files listed on command line")
for File in Args.CmdLineFileList:
File = NormalizePath(Args.UserDir, File)
DebugSpew(Args, "Examining "+File+" for inclusion in archive")
if (File in ArchFileList):
break # Don't include file if it's already there.
try:
os.stat(File)
except OSError:
print("File "+File+" listed in command line doesn't exist. Ignoring. . .")
continue
else:
ArchFileList.append(File)
# Next get file names from file, if specified.
GarchiveRCFile = open(Args.UserDir+"/"+Args.GarchiveRcFileName, "r")
DebugSpew(Args, "Examining files listed in "+Args.GarchiveRcFileName)
while 1:
FileName = GarchiveRCFile.readline()
if not FileName:
break
FileName = re.sub('[\n\s]+', '', FileName) # Strip out \n chars & whitespace
FileName = NormalizePath(Args.UserDir, FileName)
DebugSpew(Args, "Examining "+FileName+" for inclusion in archive")
try:
os.stat(FileName)
except OSError:
print("File "+FileName+" listed in "+Args.GarchiveRcFileName+" doesn't exist. Ignoring. . .")
continue
else:
FileName = NormalizePath(Args.UserDir, FileName)
if (FileName in ArchFileList):
pass
else:
ArchFileList.append(FileName)
return ArchFileList
#---------------------------------------------------------------------------
def CreateSchemFileList(Args, FileList):
"""
This creates the list of schem files to search. Right now I just
run through FileList and pull out all files ending in .sch.
Files are saved in list with basename (no path).
"""
DebugSpew(Args, "Now in CreateSchemFileList.")
SchemFileList = []
for File in FileList:
# Match *.sch
if re.search('\.sch$', File): # re.search matches occurance anywhere
# Need to make sure schem file actually exists
# There is probably a better way to do this using os.access, but I was
# not able to get it to work. . . . .
try:
TestFile = open(File, "r")
except IOError:
print("Can't access "+File+" for reading. Exiting . . . .")
sys.exit(1)
TestFile.close()
# Next we need to make sure that this file is not already in the list.
if File in SchemFileList:
pass
else:
SchemFileList.append( os.path.basename(File) )
return SchemFileList
#---------------------------------------------------------------------------
def CreateSymbolFileList(SchemFileList, LibraryFileList):
"""
This fcn opens each .sch file found and looks for symbol files
(typically lurking in lines like "C 32400 53000 1 0 0 resistor-1.sym").
When it finds a symbol file, it looks up the file's entire path, and then
sticks it in the SymbolFileList.
"""
DebugSpew(Args, "Now in CreateSymbolFileList.")
SymbolFileList = [] # List starts as empty
for SchemFileName in SchemFileList:
SchemFile = open(SchemFileName, "r")
for line in SchemFile.readlines():
# Match component line C 32400 53000 1 . . . . .
if re.match('^C ', line):
Match = re.match('(C )([\d]+ )([\d]+ )([\d]+ )([\d]+ )([\d]+ )([\d\w\-\./]+)', line)
SymFile = Match.group(7)
# DebugSpew(Args, "Found "+SymFile+" in schematic "+SchemFileName)
# Now find path for symbol file & stick it in list
for LibPath in LibraryFileList:
AbsSymFileName = os.path.abspath(LibPath+"/"+SymFile)
if os.path.isfile(AbsSymFileName):
# Insert in list if not already there.
if AbsSymFileName in SymbolFileList:
pass
else:
SymbolFileList.append(AbsSymFileName)
return SymbolFileList
#---------------------------------------------------------------------------
def CreateSPICEFileList(Args, SchemFileList):
"""
This fcn opens each .sch file found and loops through it.
While looping, it looks for SPICE files (typically lurking in lines like
"file=/path/to/spice/models/circuit.cir". When it finds a SPICE
file, it sticks it in the SPICEFileList.
The SPICE file names found are returned as absolute paths.
"""
DebugSpew(Args, "Now in CreateSPICEFIleList.")
SPICEFileList = [] # List starts as empty
SavedLine = []
for SchemFileName in SchemFileList:
# Open file in user dir.
GschemFile = open(Args.UserDir+"/"+os.path.basename(SchemFileName), "r")
for Line in GschemFile.readlines():
if (re.match('^file=', Line)):
Match = re.match('(file=)(\S+)', Line)
SPICEFile = Match.group(2)
# This needs to be more sophosticated
# SPICEFile = os.path.normpath(SPICEFile)
SPICEFile = os.path.abspath(SPICEFile)
DebugSpew(Args, "Found "+SPICEFile+" in schematic "+SchemFileName)
# Next we need to make sure that this file is not already in the list.
if SPICEFile in SPICEFileList:
pass
else:
SPICEFileList.append(SPICEFile)
return SPICEFileList
#---------------------------------------------------------------------------
def UpdateSchemFiles(Args, SchemFileList):
"""
This fcn opens each .sch file found and loops through it.
It stuffs each file line found into a list of lines. While
looping, it looks for SPICE files (typically lurking in lines like
"file=/path/to/spice/models/circuit.cir". When it finds a SPICE
file, it substitutes the line found with "file=./gschem-files/circuit.cir".
After running through the file, it closes
the file, re-opens it as write-only, and outputs the changed file.
Yes, this operation could take place in CreateSPICEFileList, but I thought
it better conceptually & architecturally to split it off to a separate fcn.
"""
DebugSpew(Args, "Now in UpdateSchemFileList.")
SavedLine = []
for SchemFileName in SchemFileList:
# Open file in user dir.
GschemFile = open(Args.ScratchDir+"/"+os.path.basename(SchemFileName), "r")
while 1:
Line = GschemFile.readline()
if not Line:
break
else:
if (re.match('^file=', Line)):
Match = re.match('(file=)(\S+)', Line)
SPICEFile = Match.group(2)
DebugSpew(Args, "Found "+SPICEFile+" in schematic "+SchemFileName)
SPICEFile = Args.FileArchiveDir+"/"+os.path.basename(SPICEFile)
DebugSpew(Args, "Updating line to point to "+SPICEFile)
SavedLine.append("file="+SPICEFile+"\n")
else:
SavedLine.append(Line)
GschemFile.close()
# Now write out list in place of file.
GschemFile = open(Args.ScratchDir+"/"+os.path.basename(SchemFileName), "w")
for Line in SavedLine:
GschemFile.write(Line)
GschemFile.close()
return
#---------------------------------------------------------------------------
def SaveSymbols(SymFileList, LibraryFileList, ArchiveDirectory):
"""
This fcn loops through all symbols in the list,
and copies the file into the local
archive.
"""
DebugSpew(Args, "Now in SaveSymbols.")
for SymFileName in SymFileList:
DebugSpew(Args, "Saving symbol "+SymFileName+" into archive "+ArchiveDirectory)
os.system("cp "+SymFileName+" "+ArchiveDirectory+"/"+os.path.basename(SymFileName) )
return
#---------------------------------------------------------------------------
def SaveSPICEFiles(SPICEFileList, ArchiveDirectory):
"""
This fcn loops through all SPICE files in the list, finds the corresponding
file somewhere in the directory tree, and then copies the file into the local
archive.
"""
DebugSpew(Args, "Now in SaveSPICEFiles.")
for SPICEFileName in SPICEFileList:
DebugSpew(Args, "Saving SPICE file "+SPICEFileName+" into archive "+ArchiveDirectory)
os.system("cp "+SPICEFileName+" "+ArchiveDirectory+"/"+os.path.basename(SPICEFileName) )
return
#---------------------------------------------------------------------------
def UpdateRC(Args):
"""
This fcn takes the gschemrc and updates it.
It runs through the file, and comments out any
occurance of (component-library. . . . Then it appends
a pointer to the local gschem-files directory
"""
DebugSpew(Args, "Now in UpdateRC.")
FileName = os.path.basename(Args.GschemRcFileName)
# First run through the file, reading the lines and building a list
# the lines found.
SavedLine = []
GschemRCFile = open(FileName, "r")
while 1:
Line = GschemRCFile.readline()
if not Line:
break
else:
if (re.match('^\(component-library', Line)):
SavedLine.append(";; "+Line) # Comment out any (component-library lines found
else:
SavedLine.append(Line)
GschemRCFile.close()
# Now write out list in place of file.
GschemRCFile = open(FileName, "w")
for Line in SavedLine:
GschemRCFile.write(Line)
# Write pointer to new lib into file
GschemRCFile.write("(component-library \"./"+Args.FileArchiveDir+"\")\n")
GschemRCFile.close()
return
#---------------------------------------------------------------------------
def IsSimpleFile(File):
"""
This fcn returns 1 if file is simple file name ("gschemrc"), or is a
simple directory name ("gschem-files"). It returns 0 if File is a
compound file name ("gschem-files/symbol-1.sym").
"""
if (os.path.basename(File) == File):
return 1 # Simple file
elif (os.path.isdir(File)):
return 1 # Directory
else:
return 0
############################################################################
# Body of archiver lives here #
############################################################################
def Archive(Args):
"""
This is the main archiver. Program algorithm is documented above. Primary
data structures are a bunch of lists holding various file names.
"""
# First check that ScratchDir is writable by the user. We will CD there
# to do real work later.
try:
TestFile = open(Args.ScratchDir+"/gschem_test", "w")
except IOError:
print("Can't work in "+Args.ScratchDir+" directory. Check that you have write permission there.")
sys.exit(1)
else:
TestFile.close()
os.remove(Args.ScratchDir+"/gschem_test")
# Create list of files (and directories) to stick into archive. Returned paths point
# to the absolute paths of the files.
ArchiveFileList = CreateArchiveFileList(Args)
# print
# print "ArchiveFileList = ",
# print ArchiveFileList
# Create list of paths to various library files. Returned paths are absolute path names
LibraryPathList = GetLibraryPath(Args)
# print
# print "LibraryPathList = ",
# print LibraryPathList
# Create list of schematic files to open and search. Returned paths
# give only the base name (i.e. no path)
SchemFileList = CreateSchemFileList(Args, ArchiveFileList)
# print
# print "SchemFileList = ",
# print SchemFileList
# Now run through SchemFileList and create list of symbols. Symbols are returned
# with only base file name (i.e. no path).
SymbolFileList = CreateSymbolFileList(SchemFileList, LibraryPathList)
# print
# print "SymbolFileList = ",
# print SymbolFileList
# Now run through SchemFileList and create list of pointers to spice files
# ("file" attributes). SPICEFiles are returned using absolute paths.
SPICEFileList = CreateSPICEFileList(Args, SchemFileList)
# print
# print "SPICEFileList = ",
# print SPICEFileList
# Now cd into /tmp dir and copy all files over to /tmp directory for processing.
os.chdir(Args.ScratchDir)
DebugSpew(Args, "Cd into "+Args.ScratchDir+" for remainder of work.")
for File in ArchiveFileList:
if (os.path.dirname(File) == Args.UserDir):
os.system("cp "+File+" "+Args.ScratchDir)
# Now run through SchemFileList and update .sch file by stuffing names
# of SPICE files into them. Save the resulting .sch files in the /tmp directory.
UpdateSchemFiles(Args,SchemFileList)
# Open gschem-files directory and stick symbol & SPICE files into into it
try:
Dir = NormalizePath(Args.ScratchDir, Args.FileArchiveDir)
os.mkdir(Dir)
except: # Directory exists.
os.system("rm -fR "+Dir) # Remove contents of old dir
os.mkdir(Dir) # Replace with new dir.
SaveSymbols(SymbolFileList, LibraryPathList, Dir)
SaveSPICEFiles(SPICEFileList, Dir)
# Now create tar file. We copy remaining files over to /tmp, and then tar them
# all up using a local, relative file prefix.
# Create string of files to archive
ArchiveString = ""
for File in ArchiveFileList:
# if (os.path.dirname(File) == Args.UserDir):
# os.system("cp "+File+" "+Args.ScratchDir)
ArchiveString = ArchiveString+" "+os.path.basename(File)
DebugSpew(Args, "Files to archive: "+ArchiveString)
# Update copy of gschemrc
UpdateRC(Args)
DebugSpew(Args, "Creating archive in "+Args.ScratchDir+" directory.")
# Now use this in tar command.
os.system("tar -cf "+Args.OutputFileNameBase+".tar "+ArchiveString)
os.system("gzip "+Args.OutputFileNameBase+".tar")
# Now try to move completed archive back to user directory.
DebugSpew(Args, "Moving archive into local directory.")
try:
os.stat(Args.UserDir+"/"+Args.OutputFileName)
except OSError: # archive is not in user directory yet, no need to force it.
os.system("mv "+Args.OutputFileName+" "+Args.UserDir)
else: # Directory already exists
Input = raw_input(Args.UserDir+"/"+Args.OutputFileName+" already exists. Overwrite? [y/N] ")
if ( (len(Input) == 0) or (Input[0] != "y") ):
print("Preserving existing archive in local directory.")
print("Your new archive lives in "+Args.ScratchDir+"/"+Args.OutputFileName)
else:
os.system("rm -fR "+Args.UserDir+"/"+Args.OutputFileName) # Remove old archive
os.system("mv "+Args.OutputFileName+" "+Args.UserDir)
print("gEDA archive "+Args.UserDir+"/"+Args.OutputFileName+" created successfully!")
# Clean up remaining mess
os.system("rm -fR "+ArchiveString)
os.chdir(Args.UserDir)
return # End of fcn . . .
############################################################################
# Body of extracter lives here #
############################################################################
def Extract(Args):
"""
This fcn extracts the archive. It tries to do it very carefully, and won't
overwrite anything you don't want it to. Algorithm:
1. copy archive file into /tmp
2. list its contents
3. Extract files indivdually, and check that each one is not present in the
destination dir before moving it.
"""
if (len(Args.CmdLineFileList) == 0):
print("Must specify a filename for extraction.")
sys.exit(1)
for FileName in Args.CmdLineFileList:
DebugSpew(Args, "Trying to extract archive "+FileName+".")
try:
os.stat(FileName)
except OSError:
print("File "+FileName+" doesn't exist. Ignoring")
continue
try:
os.system("cp -f "+FileName+" "+Args.ScratchDir)
except IOError:
print("Can't work in the "+Args.ScratchDir+" directory. Check that you have write permisison there.")
sys.exit(1)
os.chdir(Args.ScratchDir)
# Change name of file so it can be gunziped.
if not CheckFilename(FileName):
print( """
Error -- the file suffix is not \".tar.gz\"; garchive can't do extraction.
If this archive was created using garchive, you can rename it using
.tar.gz as suffix and try again. Otherwise, just gunzip and tar -xvf
the file manually.
""")
sys.exit(1)
# Now gunzip the file, then change File name to reflect new status (.tar)
os.system("gunzip -f "+FileName)
NewFileName = re.sub('\.gz', '', FileName)
# Get list of files in archive. Then open up archive
ReturnString = commands.getoutput("tar -t -f "+NewFileName)
FileList = re.split('\s+', ReturnString)
for File in FileList:
DebugSpew(Args, "Extracting "+File)
os.system("tar -f "+NewFileName+" -x "+File)
# We need to treat directories carefully. For each file, check
# if it is a simple file, a directory name, or a compound file.
for File in FileList:
if (IsSimpleFile(File)):
try:
os.stat(Args.UserDir+"/"+File)
except OSError:
os.system("mv "+File+" "+Args.UserDir)
else:
Input = raw_input(Args.UserDir+"/"+File+" already exists. Overwrite? [yN] ")
if ( (len(Input) == 0) or (Input[0] != "y") ):
print("Preserving existing "+File+" in local directory.")
else:
os.system("rm -fR "+Args.UserDir+"/"+File)
os.system("mv -f "+File+" "+Args.UserDir)
# Now clean up /tmp directory
os.system("rm -fR "+NewFileName)
os.system("rm -fR "+FileName)
os.chdir(Args.UserDir)
return # End of fcn . . . . .
############################################################################
############################################################################
# Main prog begins here #
############################################################################
############################################################################
# First get and parse command line args
Args = CmdLineArgs() # Creates Args object holding command line args info.
if Args.ProgramMode == "archive":
Archive(Args)
sys.exit(0)
elif Args.ProgramMode == "extract":
Extract(Args)
sys.exit(0)
else:
raise RuntimeError("Unknown program mode found.")
# That's it -- very simple!!
|