<commit_before>require "projsync/version"
require 'grit'
require 'colorize'


module Projsync

	class Project
		attr_accessor :name
		attr_accessor :group
		attr_accessor :path
		attr_accessor :origin

		# the block passed in is run when the project syncs
		# options:
		# * origin
		def initialize(group, name, options = {}, &block)
			@name = name
			@group = group
			@path = options[:path] || name
			@origin = options[:origin]
			@sync_block = block
		end


		def dir_path
			fp = self.path
			fp = File.join(self.group.dir_path, fp) if self.group
			File.expand_path(fp)
		end


		def exist?
			File.exist? self.dir_path
		end


		def repo
			Grit::Repo.new(self.dir_path)
		end


		def repo_dirty?
			`cd #{dir_path} && git status --porcelain` == ""
		end


		def log(type, text)
			text = "[#{name_path}] #{text}"
			case type
			when :action
				puts text.green
			when :status
				puts text.yellow
			when :error
				puts text.red
			else
				raise ArgumentError, "Unknown log typ '#{type}'"
			end
		end


		def name_path
			if self.group && self.group.name_path && self.group.name_path.length
				self.group.name_path + '/' + self.name
			else
				self.name
			end
		end


		def sync(dry_run = false)
			if exist?
				if repo_dirty?
					log :status, "Repo dirty, not fetching"
				else
					log :action, "Fetching..."
					system("cd #{dir_path} && git fetch")

					#TODO: pull
					#TODO: run sync block
					# 	@sync_block.call() if @sync_block
				end

				#TODO: push
			else
				if origin
					log :action, "Project not present, cloning from origin..."
					system("mkdir #{dir_path} && cd #{dir_path} && git clone #{origin}")
				else
					log :error, "Project not present, specify an origin in projfile and resync"
				end
			end
		end


		def inspect(indent = 0)
			"#{'  ' * indent}Project: '#{self.name}'\n"
		end
	end



	class Group
		attr_accessor :parent
		attr_accessor :subgroups
		attr_accessor :projects

		attr_accessor :name
		attr_accessor :default
		attr_accessor :path


		def initialize(parent, name, options = {})
			options = {
				default: true,
				path: name
			}.merge(options)

			@name = name
			@parent = parent
			@default = options[:default]
			@path = options[:path]
		end


		def subgroups
			@subgroups ||= []
		end


		def projects
			@projects ||= []
		end

		def name_path
			if self.parent && self.parent.name
				self.parent.name_path + '/' + self.name
			else
				self.name
			end
		end


		def dir_path
			self.parent.nil? || self.parent.dir_path.nil? ? self.path : self.parent.dir_path + '/' + self.path
		end


		def sync(options = {}, blacklist = [], whitelist = [])
			np = self.name_path
			if (self.default or whitelist.include? np) and !blacklist.include? np
				self.projects.each { |proj| proj.sync(options) }
			end

			self.subgroups.each do|subgroup|
				subgroup.sync(options, blacklist, whitelist)
			end
		end


		def inspect(indent = 0)
			i = '  ' * indent
			desc = ""
			desc += "#{i}Group: '#{self.name}'\n"

			if self.projects.length > 0
				desc = self.projects.inject(desc) do |desc, proj|
					desc + proj.inspect(indent + 1)
				end
			end

			if self.subgroups.length > 0
				desc = self.subgroups.inject(desc) do |desc, group|
					desc + group.inspect(indent + 1)
				end
			end

			desc
		end
	end



	class Manifest
		def initialize
			@tree = Group.new(nil, nil, default: true)	# root group
			@top_group = @tree
		end


		def group(path, options = {}, &block)
			g = Group.new(@top_group, path, options)
			@top_group.subgroups << g
			@top_group = g

			yield

			@top_group = @top_group.parent
		end


		def project(path, options = {}, &block)
			@top_group.projects << Project.new(@top_group, path, options, &block)
		end


		def sync(options = {}, blacklist = [], whitelist = [])
			@tree.sync(blacklist, whitelist)
		end


		def inspect
			@tree.subgroups.inject("") do |desc, group|
				desc + group.inspect(1)
			end
		end
	end
end
<commit_msg>now fetches even if repo dirty.  git pull if not dirty<commit_after>require "projsync/version"
require 'grit'
require 'colorize'


module Projsync

	class Project
		attr_accessor :name
		attr_accessor :group
		attr_accessor :path
		attr_accessor :origin

		# the block passed in is run when the project syncs
		# options:
		# * origin
		def initialize(group, name, options = {}, &block)
			@name = name
			@group = group
			@path = options[:path] || name
			@origin = options[:origin]
			@sync_block = block
		end


		def dir_path
			fp = self.path
			fp = File.join(self.group.dir_path, fp) if self.group
			File.expand_path(fp)
		end


		def exist?
			File.exist? self.dir_path
		end


		def repo
			Grit::Repo.new(self.dir_path)
		end


		def repo_dirty?
			`cd #{dir_path} && git status --porcelain` == ""
		end


		def log(type, text)
			text = "[#{name_path}] #{text}"
			case type
			when :action
				puts text.green
			when :status
				puts text.yellow
			when :error
				puts text.red
			else
				raise ArgumentError, "Unknown log typ '#{type}'"
			end
		end


		def name_path
			if self.group && self.group.name_path && self.group.name_path.length
				self.group.name_path + '/' + self.name
			else
				self.name
			end
		end

		# cd's to dir_path, then executes +cmd+ using system()
		def sh(cmd)
			system("cd #{dir_path} && #{cmd}")
		end


		def sync(dry_run = false)
			if exist?
				log :action, "Fetching..."
				sh 'git fetch'

				if repo_dirty?
					log :status, "Repo dirty, not pulling"
				else
					log :action, "Pulling..."
					sh 'git pull'

					#TODO: run sync block
					# 	@sync_block.call() if @sync_block
				end

				log :action, "Pushing..."
				sh 'git push'
			else
				if origin
					log :action, "Project not present, cloning from origin..."
					system("mkdir -p #{dir_path}")
					sh "git clone #{origin}"
				else
					log :error, "Project not present, specify an origin in projfile and resync"
				end
			end
		end


		def inspect(indent = 0)
			"#{'  ' * indent}Project: '#{self.name}'\n"
		end
	end



	class Group
		attr_accessor :parent
		attr_accessor :subgroups
		attr_accessor :projects

		attr_accessor :name
		attr_accessor :default
		attr_accessor :path


		def initialize(parent, name, options = {})
			options = {
				default: true,
				path: name
			}.merge(options)

			@name = name
			@parent = parent
			@default = options[:default]
			@path = options[:path]
		end


		def subgroups
			@subgroups ||= []
		end


		def projects
			@projects ||= []
		end

		def name_path
			if self.parent && self.parent.name
				self.parent.name_path + '/' + self.name
			else
				self.name
			end
		end


		def dir_path
			self.parent.nil? || self.parent.dir_path.nil? ? self.path : self.parent.dir_path + '/' + self.path
		end


		def sync(options = {}, blacklist = [], whitelist = [])
			np = self.name_path
			if (self.default or whitelist.include? np) and !blacklist.include? np
				self.projects.each { |proj| proj.sync(options) }
			end

			self.subgroups.each do|subgroup|
				subgroup.sync(options, blacklist, whitelist)
			end
		end


		def inspect(indent = 0)
			i = '  ' * indent
			desc = ""
			desc += "#{i}Group: '#{self.name}'\n"

			if self.projects.length > 0
				desc = self.projects.inject(desc) do |desc, proj|
					desc + proj.inspect(indent + 1)
				end
			end

			if self.subgroups.length > 0
				desc = self.subgroups.inject(desc) do |desc, group|
					desc + group.inspect(indent + 1)
				end
			end

			desc
		end
	end



	class Manifest
		def initialize
			@tree = Group.new(nil, nil, default: true)	# root group
			@top_group = @tree
		end


		def group(path, options = {}, &block)
			g = Group.new(@top_group, path, options)
			@top_group.subgroups << g
			@top_group = g

			yield

			@top_group = @top_group.parent
		end


		def project(path, options = {}, &block)
			@top_group.projects << Project.new(@top_group, path, options, &block)
		end


		def sync(options = {}, blacklist = [], whitelist = [])
			@tree.sync(blacklist, whitelist)
		end


		def inspect
			@tree.subgroups.inject("") do |desc, group|
				desc + group.inspect(1)
			end
		end
	end
end

{'fraction_non_alphanumeric': 0.12346749226006191, 'fraction_numerical': 0.0017337461300309597, 'mean_word_length': 2.67592171142467, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5167581', 'n_tokens_mistral': 3545, 'n_tokens_neox': 2840, 'n_words': 775}