2 # primary functions and glue for generating the repository metadata
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Library General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 # Copyright 2004 Duke University
19 # Portions Copyright 2009 Red Hat, Inc -
20 # written by seth vidal skvidal at fedoraproject.org
25 from optparse import OptionParser
29 from createrepo import MDError
30 from createrepo.utils import errorprint, _
34 def parse_args(args, conf):
36 Parse the command line args. return a config object.
37 Sanity check all the things being passed in.
40 _def = yum.misc._default_checksums[0]
41 _avail = yum.misc._available_checksums
42 parser = OptionParser(version = "createrepo %s" % createrepo.__version__)
44 parser.add_option("-q", "--quiet", default=False, action="store_true",
45 help="output nothing except for serious errors")
46 parser.add_option("-v", "--verbose", default=False, action="store_true",
47 help="output more debugging info.")
48 parser.add_option("--profile", default=False, action="store_true",
49 help="output timing/profile info.")
50 parser.add_option("-x", "--excludes", default=[], action="append",
51 help="files to exclude")
52 parser.add_option("--basedir", default=os.getcwd(),
53 help="basedir for path to directories")
54 parser.add_option("-u", "--baseurl", default=None,
55 help="baseurl to append on all files")
56 parser.add_option("-g", "--groupfile", default=None,
57 help="path to groupfile to include in metadata")
58 parser.add_option("-s", "--checksum", default=_def, dest='sumtype',
59 help="specify the checksum type to use (default: %s)" % _def)
60 parser.add_option("-p", "--pretty", default=False, action="store_true",
61 help="make sure all xml generated is formatted")
62 parser.add_option("-c", "--cachedir", default=None,
63 help="set path to cache dir")
64 parser.add_option("-C", "--checkts", default=False, action="store_true",
65 help="check timestamps on files vs the metadata to see " \
66 "if we need to update")
67 parser.add_option("-d", "--database", default=True, action="store_true",
68 help="create sqlite database files: now default, see --no-database to disable")
69 parser.add_option("--no-database", default=False, dest="nodatabase", action="store_true",
70 help="do not create sqlite dbs of metadata")
71 # temporarily disabled
72 #parser.add_option("--database-only", default=False, action="store_true",
73 # dest='database_only',
74 # help="Only make the sqlite databases - does not work with --update, yet")
75 parser.add_option("--update", default=False, action="store_true",
76 help="use the existing repodata to speed up creation of new")
77 parser.add_option("--update-md-path", default=None, dest='update_md_path',
78 help="use the existing repodata for --update from this path")
79 parser.add_option("--skip-stat", dest='skip_stat', default=False,
80 help="skip the stat() call on a --update, assumes if the file" \
81 "name is the same then the file is still the same " \
82 "(only use this if you're fairly trusting or gullible)",
84 parser.add_option("--split", default=False, action="store_true",
85 help="generate split media")
86 parser.add_option("-i", "--pkglist", default=None,
87 help="use only the files listed in this file from the " \
88 "directory specified")
89 parser.add_option("-n", "--includepkg", default=[], action="append",
90 help="add this pkg to the list - can be specified multiple times")
91 parser.add_option("-o", "--outputdir", default=None,
92 help="<dir> = optional directory to output to")
93 parser.add_option("-S", "--skip-symlinks", dest="skip_symlinks",
94 default=False, action="store_true", help="ignore symlinks of packages")
95 parser.add_option("--changelog-limit", dest="changelog_limit",
96 default=None, help="only import the last N changelog entries")
97 parser.add_option("--unique-md-filenames", dest="unique_md_filenames",
98 help="include the file's checksum in the filename, helps with proxies",
99 default=True, action="store_true")
100 parser.add_option("--simple-md-filenames", dest="simple_md_filenames",
101 help="do not include the file's checksum in the filename, helps with proxies",
102 default=False, action="store_true")
103 parser.add_option("--distro", default=[], action="append",
104 help="distro tag and optional cpeid: --distro" "'cpeid,textname'")
105 parser.add_option("--content", default=[], dest='content_tags',
106 action="append", help="tags for the content in the repository")
107 parser.add_option("--repo", default=[], dest='repo_tags',
108 action="append", help="tags to describe the repository itself")
109 parser.add_option("--revision", default=None,
110 help="user-specified revision for this repository")
111 parser.add_option("--deltas", default=False, action="store_true",
112 help="create delta rpms and metadata")
113 parser.add_option("--oldpackagedirs", default=[], dest="oldpackage_paths",
114 action="append", help="paths to look for older pkgs to delta against")
115 parser.add_option("--num-deltas", default=1, dest='num_deltas', type='int',
116 help="the number of older versions to make deltas against")
117 parser.add_option("--read-pkgs-list", default=None, dest='read_pkgs_list',
118 help="output the paths to the pkgs actually read useful with --update")
119 parser.add_option("--max-delta-rpm-size", default=100000000,
120 dest='max_delta_rpm_size', type='int',
121 help="max size of an rpm that to run deltarpm against (in bytes)")
123 parser.add_option("--workers", default=1,
124 dest='workers', type='int',
125 help="number of workers to spawn to read rpms")
127 (opts, argsleft) = parser.parse_args(args)
128 if len(argsleft) > 1 and not opts.split:
129 errorprint(_('Error: Only one directory allowed per run.'))
133 elif len(argsleft) == 0:
134 errorprint(_('Error: Must specify a directory to index.'))
139 directories = argsleft
141 if opts.sumtype == 'sha1':
142 errorprint(_('Warning: It is more compatible to use sha instead of sha1'))
144 if opts.sumtype != 'sha' and opts.sumtype not in _avail:
145 errorprint(_('Error: Checksum %s not available (sha, %s)') %
146 (opts.sumtype, ", ".join(sorted(_avail))))
149 if opts.split and opts.checkts:
150 errorprint(_('--split and --checkts options are mutually exclusive'))
153 if opts.simple_md_filenames:
154 opts.unique_md_filenames = False
157 opts.database = False
159 # let's switch over to using the conf object - put all the opts into it
160 for opt in parser.option_list:
161 if opt.dest is None: # this is fairly silly
163 # if it's not set, take the default from the base class
164 if getattr(opts, opt.dest) is None:
166 setattr(conf, opt.dest, getattr(opts, opt.dest))
168 directory = directories[0]
169 conf.directory = directory
170 conf.directories = directories
174 for spec in opts.distro:
175 if spec.find(',') == -1:
176 conf.distro_tags.append((None, spec))
178 splitspec = spec.split(',')
179 conf.distro_tags.append((splitspec[0], splitspec[1]))
183 pfo = open(conf.pkglist, 'r')
184 for line in pfo.readlines():
186 if re.match('^\s*\#.*', line) or re.match('^\s*$', line):
194 conf.pkglist.extend(conf.includepkg)
196 if conf.changelog_limit: # make sure it is an int, not a string
197 conf.changelog_limit = int(conf.changelog_limit)
201 class MDCallBack(object):
202 """cli callback object for createrepo"""
204 self.__show_progress = os.isatty(1)
206 def errorlog(self, thing):
207 """error log output"""
208 print >> sys.stderr, thing
210 def log(self, thing):
214 def progress(self, item, current, total):
217 if not self.__show_progress:
219 beg = "%*d/%d - " % (len(str(total)), current, total)
221 sys.stdout.write("\r%s%-*.*s" % (beg, left, left, item))
225 """createrepo from cli main flow"""
226 start_st = time.time()
227 conf = createrepo.MetaDataConfig()
228 conf = parse_args(args, conf)
230 print ('start time: %0.3f' % (time.time() - start_st))
235 mdgen = createrepo.SplitMetaDataGenerator(config_obj=conf,
236 callback=MDCallBack())
238 mdgen = createrepo.MetaDataGenerator(config_obj=conf,
239 callback=MDCallBack())
240 if mdgen.checkTimeStamps():
241 if mdgen.conf.verbose:
242 print _('repo is up to date')
246 print ('mid time: %0.3f' % (time.time() - mid_st))
249 mdgen.doPkgMetadata()
251 print ('pm time: %0.3f' % (time.time() - pm_st))
253 mdgen.doRepoMetadata()
255 print ('rm time: %0.3f' % (time.time() - rm_st))
259 print ('fm time: %0.3f' % (time.time() - fm_st))
262 except MDError, errormsg:
263 errorprint(_('%s') % errormsg)
267 if __name__ == "__main__":
268 if len(sys.argv) > 1:
269 if sys.argv[1] == 'profile':
271 p = hotshot.Profile(os.path.expanduser("~/createrepo.prof"))
272 p.run('main(sys.argv[2:])')